Map, switchMap, mergeMap, flatMap, concatMap, exhaustMap in RxJS - what is the difference?
In this post you will learn once and forever what is the difference between map methods inside RxJS. It is map
, switchMap
, concatMap
, flatMap
, mergeMap
and exhaustMap
.
The main problem is that it is really difficult to understand the difference between all this methods. You open documentation, you might understand one method and then you don't understand in what case what method you should use.
Then you jump to Stack Overflow to solve your specific problem and you see that people use different methods for exactly the same solution. Then you are wondering if it makes any difference at all to use some of these methods.
This is why here I prepared for you a simple example to understand all these methods.
Map
The first method here is map
. Actually map
is completely different from other methods. When we use map
we simply want to change the source of our stream without usage of subscribe
.
foo$ = from([1,2,3,4,5]).pipe(map((item) => item * 10))
Here we used from
to create a changed stream. In order to modify every single element we transform them with map
. This allows us to multiply them by 10 in this case.
As you can see we are getting multiplied values.
We are using map when we transform values of our stream without using subscribe.
In order to understand other methods I have an additional function.
const example = (operator: any) => () => {
from([0, 1, 2, 3, 4])
.pipe(operator((x: any) => of(x).pipe(delay(500))))
.subscribe(
console.log,
() => {},
() => console.log(`${operator.name} completed`)
);
};
//example(mergeMap)();
Here we will throw different operators inside example
function and check how they work. Inside we create a stream from 0 to 4 and create a new stream with 500 ms delay for every value.
mergeMap / flatMap
First let's talk about mergeMap
and flatMap
. You must remember that flatMap
is just an alias to mergeMap
and it is deprecated inside RxJS.
As you can see we directly get all these values inside console with a single 500ms delay. mergeMap
creates directly observable from our source but it doesn't cancel any existing observables.
Every single time when we create new observable from our value and delay it we jump directly to the next value without waiting for first observable to complete.
So with mergeMap
all previous observables are ignored and we simply create new one.
If we try to change mergeMap
to flatMap
you will see the same result as this is just an alias.
concatMap
The next one in our list of concatMap
.
The difference here is that we can see the delay 500ms between every value. Which means with concatMap
we are waiting for previous observable to complete before we create a new observable.
concatMap waits for previous observable to be completed.
The usage of concatMap
is when you need to create an observable based on the previous observable. mergeMap
on the other hand won't wait for the result.
switchMap
Now let's try switchMap
.
As you can see we get just 4
.
switchMap cancels every previous observable
When we create observable for 0
and we delay it with 500ms we directly create an observable for 1
which cancels our observable for 0
. This is why at the end we just get a single observable of 4
.
exhaustMap
The last method that we want to check is exhaustMap
.
Here we get just 0
because all next observables are ignored until the first one won't be completed. As our first observable is being delayed by 500ms we ignore all other observables. This is why we see just 0
.
Real problem
Here is an example of real use case when we want to make 2 API requests one by one. Because second request needs result from the first one we want to wait for the completion. This is why in the code you can see that we used concatMap
. This is the most correct way and in browser we can see detail information as a result.
But we can easily change concatMap
to switchMap
at it will bring exactly the same result. Yes switchMap
cancels the previous observable but with a single value as an API response it doesn't matter so in this case both these methods are working the same.
But this is exactly what leads to the confusion if you don't know the differences between these methods.
Want to conquer your next JavaScript interview? Download my FREE PDF - Pass Your JS Interview with Confidence and start preparing for success today!