RxJS Mapping: Behind the scenes
Tags: switchmap, exhaustmap, mergemap, concatmap
Published: 2024-05-29 08:36:32

Photo by <a href="https://unsplash.com/@zvessels55?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">TopSphere Media</a> on <a href="https://unsplash.com/photos/black-camera-on-gray-concrete-floor-M2zgw2alz3c?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Unsplash</a>
  
A hands-on look at how higher-order operators work behind the scenes.

SwitchMap, MergeMap, ConcatMap, or ExhaustMap? Choosing the right one can be confusing, but we'll unravel their differences by taking a peek behind the scenes. 

To make things even more exciting, I'll provide a simulator at the end so you can interact with the maps and see their differences come to life.


## Map suffix
**Why do we need higher-order operators?**

Higher-order operators are necessary to handle higher-order observables, which are observables of observables. In the context of higher-order observables, we have inner and outer (source) observables. Whenever a new page is emitted (outer), we make an HTTP request (inner) to retrieve the corresponding data.

```javascript
const data = pageObservable$.pipe(
 higherOrderOperatorHere(page => http.get(page));
);
```

**What does it mean to "handle" higher-order observables?**

When we use an ordinary RxJS map operator, each page number is mapped to an Observable, resulting in observing observables instead of values.

```javascript
const data: Observable<Observable<Data>> = pageObservable$.pipe(
 map(page => http.get(page));
);
```
Higher-order operators handle exactly that, plus some additional functionality depending on the prefix (switch, merge, exhaust, and concat).
```javascript
const data: Observable<Data> = pageObservable$.pipe(
 higherOrderOperatorHere(page => http.get(page));
);
```

## Switch, Exhaust, Merge, or Concat
Switch, exhaust, merge, and concat are policies for managing concurrency between inner observables. This concurrency arises from the asynchronous processing of each source.

Let's explore each of these operators and their functions. We will illustrate this entire process using a finite-state machine.

### SwitchMap
![SwitchMap](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9son9q704kirlb6al5k3.png)
**States**: [Start, Active, Canceled, Completed]
**Final states**: [Canceled, Completed]
**Transitions**: 

From Start to Active
Condition: new source emitted.

From Active to Completed
Condition: inner observable completed.

From Active to Canceled
Condition: new source emitted.

### ExhaustMap

![exhaustMap](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ojodhitvjlpyekisdx8w.png)
**States**: [Start, Active, Canceled, Completed]
**Final states**: [Canceled, Completed]
**Transitions**: 

From Start to Active
Condition: new source emitted & no other active inner observable.

From Start to Canceled
Condition: new source emitted & other active inner observable.

From Active to Completed
Condition: inner observable completed.

### MergeMap

![mergeMap](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yqu6q0mcf5sbyhjmp8gm.png)
**States**: [Start, Active, Completed]
**Final state**: Completed

**Transitions**:

From Start to Active
Condition: new source emitted.

From Active to Completed
Condition: inner observable completed.

### ConcatMap

![concatMap](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/anw3iv38rvxscqaqu9y4.png)
**States**: [Start, Queued, Active, Completed]
**Final state**: Completed

**Transitions**:

From Start to Active
Condition: new source emitted & no other active inner observable.

From Start to Queued
Condition: new soure emitted & other active inner observable.

From Active to Completed
Condition: inner observable completed.

From Queued to Active
Condition: head of the queue & no other active inner observable.

## Hands-On Demo

_When I said "hands-on look" I meant it literally._
Set up a scenario and see how the maps behave!


{% embed https://stackblitz.com/edit/stackblitz-starters-mipoqw?embed=1&file=src%2Fapp%2Fdata%2Fsource.data.ts %}

## Thanks for reading!
P.S. If you are interested in practical examples of using these operators, take a look at this article.

{% embed https://dev.to/strahinja_obradovic/from-imperative-to-declarative-angular-development-with-rxjs-374j %}