When do you use which RxJS mapping operator?
Anyone who has built an application with Angular or who has used RxJS does know the different RxJS operators and in most cases the usual suspect ‘map’ operator. But when do you use which mapping operator? You can use i.e. the most simple ‘map’ operator but also the more advanced mergeMap, concatMap, exhaustMap and switchMap operators. The comments on the internet are not so clear and everyone has his own idea on when to use which operator.
In the code sample below you can see a simple ‘map’ operator used for mapping the strings from a observable to a more extended string:
This works just fine on simple values or objects, but things get a little bit more complicated when dealing with more complex things…
When calling an API or when you’re connected via a Websocket and you want to directly use the observable without subscribing, you’ll need to map these values and return their inner observable. You could try to do that by again using the simple ‘map’ operator, but this will result in the following code sample:
Since the map operator doesn’t do any ‘flattening’ of the inner observable, we just get a returned observable wrapped in another observable, which is useless to work with.
RxJS provides for these more advanced operations mapping operators that can do mapping but also flattening. Flattening is the process you would typically do in the subscribe on an observable. Basically you’re going to subscribe on an outer observable and in that subscribe you’re going to subscribe again on the (inner) observable emitted by the outer observable. You could do this by using the simple ‘map’ operator and just following the above described sentence as you can see in the code sample below:
However, doing a subscribe in another subscribe is bad practice and can cause memory leaks in your application. To fix this problem, you can use the more advanced mapping operators that do the mapping + flattening all in one operator.
Fixing the code with a mergeMap operator would look like this:
the mergeMap operator first does the mapping of the outer observable values and flattens the returned inner observables so that we can use it in our outer subscription
The difference between the advanced mapping operators
As mentioned before, you have different advanced mapping operators; mergeMap, concatMap, exhaustMap and the switchMap operator. In general terms, every advanced mapping operator does the same thing. It just does mapping + flattening of an observable, but every operator has his own different outcome.
Imagine yourself trying to get a coffee in a coffee bar. You and another person are waiting for the bar to open. The barista is getting everything ready and is going to open the bar. From here on the mapping operators will decide how you and the other person will create the queue for getting that coffee.
MergeMap: As soon as the bar opens you and the other person are running to the barista in chaos and trying to get there first. There is no clear queue and you two could potentially order your coffee at the exact same time.
ConcatMap: As soon as the bar opens you and the other person are getting in a nice queue and get served by the barista in the order you’re queueing. First come, first served not matter how long the queue gets. This could potentially cause the problem that the queue gets very large and that other people at the end of the queue would have to wait a very long time for their coffee.
ExhaustMap: As soon as the bar opens you’re standing in a fair queue with the other person standing behind you. However, the order is taking too long for the other person behind you and he leaves the bar without his or her cup of coffee.
SwitchMap: As soon as the bar opens, you order a coffee. A few seconds later the other guy arrives and he just gets in front of you, ordering his coffee. unfortunately your order is getting cancelled by the barista and the other guy is getting his coffee unless another person arrives, which would cancel his or her order as well.
All advanced mapping operators act in a same way mapping + flattening, but can have different outcomes depending on the context or situation.
mergeMap: alias for flatMap. Combine the results of two HTTP calls into a single result set.
concatMap: run an operation on each entry in a queue, and respect the order of the queue.
exhaustMap: when a login HTTP call takes some time, we don’t care if the user keeps retrying. We only try again when we’re done.
switchMap: when listening to a mouse move event, we only care for the current position. Older position values should be ignored.
Good use cases for every operator (these are only a general rule of thumb):
- mergeMap: delete operations since the order does not matter and the end result should be that everything is deleted.
- concatMap: update or create operations since a create or update operation can be time sensitive and every operation should be handled no matter how long it would take.
- exhaustMap: non parameterized queries since the results will probably be the same.
- switchMap: parameterized queries since a delayed query would contain more recent query params which will let to the more relevant information you’re asking for.
Kevin Buschgens (25) behaalde een Bachelor Toegepaste Informatica aan de PXL met als afstudeerrichting “Software Management”. Momenteel is Kevin aan de slag bij TrendMiner op de Corda Campus in Hasselt, waar hij dagelijks met de laatste versies van state of the art technologieën werkt.