Understanding mergeMap and switchMap in RxJS

Netanel Basal
Netanel Basal
Published in
4 min readJan 24, 2018

--

Higher order observables are one of the most influential features in Rx. They’re also one of the most difficult to understand.

In this article, I will try to explain the subject in my own way. Hopefully, it will shine some light in the dark.

Let’s say you have a simple task. You have a button, and when you click on it, you need to start an interval. Let’s see how we would implement this the simple way.

click to interval

We need to subscribe to the fromEvent() observable, which internally adds a new click event listener to our button. When the user clicks on the button, we need to subscribe to the interval() observable, which internally invokes the native JS setInterval() function.

clicking ones

While it works fine, there are two drawbacks to the code above.
1. It’s starting to look like callback hell.
2. We need to handle the disposal of every subscription by ourselves.

Let’s see how higher order observables make things easier for us.

Higher Order Observables

An observable can emit values of any type: numbers, strings, objects, etc. This means an observable can also emit values that are, themselves, observables too.

A higher order observable is just a fancy name for an observable that emits observable. Let’s change the example a little bit so you can see what I’m talking about.

clicks$ to interval$

When the user clicks on the button, we leverage the map() operator to return an interval() observable to the stream.

When we subscribe, the clicks$ observable will next() an interval observable.

Clicking multiple times

You may notice that, in this case, we never invoke the interval. In contrast, in the first example, we saw the numbers running in the console.

That’s because we never called subscribe() on our interval$ observable. Remember that observables are lazy — if we want to pull a value out of an observable, we must subscribe().

clicksToIntervals subscribe

Now, we are going to once again see the numbers from our interval observable.

Now that we understand the nature of higher order observables, let’s introduce two useful operators to help us with the problems mentioned above.

mergeAll

When the inner observable emits, let me know by merging the value to the outer observable.

Under the hood, the mergeAll() operator basically does what we did in the last example. It takes the inner observable, subscribes to it, and pushes the value to the observer.

mergeAll

In our case, the source ( or outer ) observable is the clicks$ observable and the inner observable is the interval$ observable.

Because this is a common pattern in Rx, there is a shortcut that achieves the same behaviour — mergeMap().

mergeMaP

So mergeMap() is just map() + mergeAll().

Here’s a very basic implementation of mergeMap():

mergeMap

From the above code, we can learn that each time we click on the button, we are invoking the subscribe() method of the inner interval() observable — which leads to multiple independent intervals in our page.

If this is what you’re after, you are good to go. But, if you want to cancel the previous subscriptions and keep only one, you’ll need the switch() operator.

switch

Like mergeMap() but when the source observable emits cancel any previous subscriptions of the inner observable.

As the name suggests, switch() switches to the new subscription and cancels the previous one.

If we change our code to switch() and click on the button multiple times, we’ll see that each time we click we are given a new interval and the previous one is canceled.

switch
Clicking three times

As you can see, even after clicking three times, we have only one interval running. In contrast, with the merge() operator, we would have three independent intervals. Essentially, the key difference between merge() and switch() is one important line.

switchMap

When the source emits, we need to unsubscribe from the previous inner subscription.

Because this is a common pattern in Rx, there is a shortcut to achieve the same behaviour — switchMap().

So switchMap() is just map() + switch().

Summary

We learned about higher order observables and the difference between mergeMap() and switchMap(). As a rule of thumb, if you don’t know what you’re doing, switchMap() is a better choice.

🚀 In Case You Missed It

  • Akita: State Management Tailored-Made for JS Applications
  • Spectator: A Powerful Tool to Simplify Your Angular Tests
  • Transloco: The Internationalization library Angular

Follow me on Medium or Twitter to read more about Angular, Vue and JS!

--

--

A FrontEnd Tech Lead, blogger, and open source maintainer. The founder of ngneat, husband and father.