DEV Community

Hssan Bouzlima
Hssan Bouzlima

Posted on

switchMap, mergeMap, concatMap, and exhaustMap like you have never seen

switchMap, mergeMap, concatMap and exhaustMap are rxjs flattening operatators.

They are considered as transformational operators since they transform an observable after applying a function, to a new observable.

They help us to avoid situation where we have to nest subscription and things get messy.

For example, when a user clicks a submit button (source observable), an http request is sent to the server (inner observable), then, we listen to the response.

A simpler example would be as follows :

nested subscription

The difference between them is based on the manner in which they act when the source observable emits while the inner subscription still in progress.

Imagine this user clicks the submit button, an http request is sent to the server, while we are waiting for a response he clicks again on the button.

What should inner observable do?πŸ€”

cancels active subscription and starts new one?
maintains active subscription and ignores new one?
maintains active subscription and starts new one?

To anwser these questions and more, we will make things simpler.

We will imagine the source observable as client orders in restaurant, and, inner observable as a chef response to these orders.

πŸ‘¨β€πŸ³ πŸ™‹β€β™‚οΈ

chef client illustration

chef client orders

orders are observable of strings representing different client orders. πŸ‘¨

prepareOrder will be the projection function, it takes an order as observable. After preparing the order (it takes random time ⏲️ ) it sends back a new observable (inner observable). 🍚

mergeMap 🀯

mergeMap

Result:

mergeMap result

We get order 2, 3, 4, then 1.
It seems like mergeMap does not respect orders sequence !.

let's see what happens with this chef:

While he is preparing an order, he is also listening for new orders, when he gets one, he starts immediately treating the new order even the current one is not yet completed, then, he sends back the first that gets completed and so on.

He treats orders concurrently !

concatMap πŸ˜‡

concatMap

Result

concatMap result

We get orders in sequence 1, 2, 3, then 4.

Wow this chef respect orders sequence !

Even though order 4 took only 12 ms to be ready and order 1 took 685 ms, he responded to order 1 before order 4 !

What happens?

This chef listen to orders in sequence. While he is in the middle of preparing an order and new one comes, he takes note of this order (in buffer) to get back to it after finishing current order and so on.

exhaustMap πŸ™„

exhaustMap

Result

exhaustMap result

This chef is so lazy, he responded only to the first order !

When he is preparing an order, he will ignore any order in meantime until he finishes the current one.

switchMap 😈

switchMap

Result

switchMap result

He responded only to order 4 !

This chef is unkind ! When he is preparing an order and gets new one, he drops the current order and starts immediately preparing the new order.

Let's summarize:

How flattening operators would represent themselves if they were chefs?

-🀯mergeMap: I'm a hard worker, I can prepare multiple orders at the same time ! But I don't respect orders sequence.

-πŸ˜‡concatMap: I respect orders sequence! You will get your order as soon as I finish what I'm currently doing.

-πŸ™„exhaustMap: I'm exhausted ! when I prepare an order, I won't listen to any other order.

-😈switchMap: I'm mean ! your order will be in trash if I receive new one.

That's it !

Hope this illustration makes it easier to understand these operators. And helps you choose the best operator that fits your use case.

You find more details in official rxjs docs and learnrxjs.io

Github
Linkedin

Discussion (1)

Collapse
ramprakashram profile image
Ram

Wow this example with your explanation gave me a much clearer understanding of these operators than before.