switchMap, mergeMap, concatMap, and exhaustMap like you have never seen
Tags: javascript, angular, webdev
Published: 2021-09-05 14:55:43

*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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8x3sokdmqx3k3is0ghn4.png)



*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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/opnufn1l9w65rr5x0cxa.jpg)


![chef client orders](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/od6endhw0leox5lnc7g7.png)

***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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aanna6izb8vyshpdjxpu.png) 

*Result:*

![mergeMap result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/achrf22vsswnt0xrwn9n.JPG) 

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xjdept9il3ndd200x879.png) 

*Result* 

![concatMap result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/orabnle6mw19xatj0bwr.JPG) 

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k9zusf5j5unrglxbg635.png) 

*Result*

![exhaustMap result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uzfath9raggbwugzo2ps.JPG)


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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bzj5bjcknzbauji1yxnm.png) 

*Result*

![switchMap result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iqea48nnigxvqglaup0q.JPG) 

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](https://rxjs.dev/) and [learnrxjs.io](https://www.learnrxjs.io/)   

[Github](https://github.com/hssanbzlm)
[Linkedin](https://www.linkedin.com/in/hssanbouzlima/)