RxJS (Reactive Extensions for JavaScript) operators are functions that allow you to manipulate the items that are emitted by Observables in various ways. These operators can filter, combine, transform, and perform many other operations on Observable streams. The operators switchMap
, concatMap
, exhaustMap
, and mergeMap
are all part of a category known as higher-order mapping operators. They are used to handle Observable inputs and return new Observables. Let’s go through each of them, including how they differ from each other:
When a new Observable is emitted, switchMap
will unsubscribe from the previous Observable and subscribe to the new Observable. This is useful for canceling in-flight network requests if a new request comes in.
Ideal for scenarios like search typeaheads where you only care about the latest emitted value and want to cancel previous requests.
const btn = document.getElementById('button');
const btnClick$ = fromEvent(btn, 'click');
const data$ = timer(0, 500).pipe(take(10));
const observer$ = btnClick$.pipe(switchMap(() => data$)).subscribe({
next: (i) => console.log(i + 1),
complete: () => console.log('complete'),
});
concatMap
will queue and subscribe to Observables one after another. It waits for each Observable to complete before subscribing to the next one. This ensures that the order of the Observables is maintained.
This is useful in scenarios where you want to prevent new subscriptions while processing a current one, such as preventing multiple clicks from triggering more actions until the current action is completed.
const btn = document.getElementById('button');
const btnClick$ = fromEvent(btn, 'click');
const data$ = timer(0, 500).pipe(take(5));
const observer$ = btnClick$.pipe(concatMap(() => data$)).subscribe({
next: (i) => {
console.log(i + 1);
},
complete: () => console.log('complete'),
});
mergeMap
subscribes to all emitted Observables immediately and merges their emissions into a single Observable output. It does not wait for Observables to complete and can handle multiple Observables concurrently.
Useful in scenarios where you want to handle multiple operations in parallel without waiting for them to complete sequentially, such as triggering multiple, independent network requests simultaneously.
const btn = document.getElementById('button');
const btnClick$ = fromEvent(btn, 'click');
const data$ = timer(0, 500).pipe(take(5));
const observer$ = btnClick$.pipe(mergeMap(() => data$)).subscribe({
next: (i) => {
console.log(i + 1);
},
complete: () => console.log('complete'),
});