The Simple Difference Between RxJS switchMap and mergeMap
…when dealing with HTTP requests
Have you been reading about RxJS for the past hour or so, trying to figure out whether you should be using switchMap
or mergeMap
to handle a simple HTTP request?
That’s exactly what happened to me today, and none of the articles explained the difference in a way that I could understand — there were long paragraphs describing all the details, with many examples using intervals, marble diagrams, and creative analogies.
After all that reading, I only started understanding when I tried it out for myself.
Use case
Let’s get right to it — I wanted to write an @ngrx/effect
to send an HTTP request to a metrics service whenever an action was dispatched to the store.
switchMap
Here’s what I came up with initially using switchMap
:
import { Injectable } from '@angular/core';
import { of } from 'rxjs/observable/of';
import { catchError } from 'rxjs/operators/catchError';
import { switchMap } from 'rxjs/operators/switchMap';@Injectable()
export class MetricsEffects {
@Effect({ dispatch: false })
public readonly logToMetrics$ = this.actions$.pipe(
switchMap((action) => this.metricsService.log(action).pipe(
catchError(of)
))
);
constructor(
private actions$: Actions,
private metricsService: MetricsService,
) {
}
}
However, after making 8 requests in quick succession, here’s what the results looked like:
You’ll notice some of those requests got cancelled before they finished. Much like takeLatest
in Redux-Saga, switchMap
in RxJS only cares about the latest value that the observable emitted, in this case cancelling any previous HTTP requests that were still in progress.
But that wasn’t exactly what I needed.
mergeMap
So let’s try running another 8 requests using mergeMap
instead:
...
public readonly logToMetrics$ = this.actions$.pipe(
mergeMap((action) => this.metricsService.log(action).pipe(
catchError(of)
))
);
...
The results this time are:
Much like takeEvery
in Redux-Saga, mergeMap
in RxJS passes all requests through, even when a new request was made before a previous one had finished — exactly what I needed!
Conclusion
So here’s the simple difference — switchMap
cancels previous HTTP requests that are still in progress, while mergeMap
lets all of them finish.
In my case, I needed all requests to go through, as this is a metrics service that’s supposed to log all actions that the user performs on the web page, so I used mergeMap
.
A good use case for switchMap
would be an autocomplete input, where we should discard all but the latest results from the user’s input.
Did this help with understanding when to use which? Let me know in the comments 👇