W dzisiejszym wpisie poruszę temat różnic pomiędzy operatorami switchMap()
i mergeMap()
z biblioteki RxJS – czym się różnią i kiedy mogą okazać się przydatne?
Po co tak właściwie nam te operatory?
Operatory switchMap() i mergeMap() dają nam możliwość subskrypcji do observabli/subjectów z uniknięciem antywzorca zagniżdżonych subskypcji (ang. nested subscriptions). Czyli zamiast:
this.myService.getCustomerId().subscribe((id: number) => {
this.myService
.getCustomerData(id)
.subscribe((data: customerData) => this.updateView(data));
});
Możemy uzyskać taki kod z wykorzystaniem operatora switchMap:
this.myService
.getCustomerId()
.pipe(switchMap((id: number) => this.myService.getCustomerData(id)))
.subscribe((data: customerData) => this.updateView(data));
switchMap()
Operator switchMap() jest jednym z wielu pipe operatorów w bibliotece RxJS. Używamy go w momencie kiedy spodziewamy się dużej ilości subskrypcji wewnętrznych ale z pewnych względów nie zależy nam aby wszystkie zostały wykonane a tylko ta ostatnia.
Przykład w kodzie:
const saveLocation = (location) => {
return of(location).pipe(delay(500));
};
const click$ = fromEvent(document, 'click');
let counter = 0;
click$
.pipe(
switchMap((e: MouseEvent) => {
return saveLocation({
timestamp: Date.now(),
counter: counter++,
});
})
)
.subscribe((r) => console.log('Saved!', r));
Ten sam przykład na stackblitz.
Dzięki zastosowaniu operatora delay()
możemy zasymulować wykonywanie się requestu. Jak widać po wielokrotnym kliknięciu na stronie, w naszej konsoli ukazuje się taki oto obraz:

Żądania od 0 do 2 nie zostały wykonane (patrz zmienna „counter”). Wykonało się natomiast tylko ostatnie kliknięcie (numer 3).
mergeMap()
Operatora mergeMap()
używamy kiedy zależy nam aby każde żądanie zostało wykonane w momencie jego nadejścia (nawet wtedy kiedy poprzednie nie zostało jeszcze zakończone).
Przykład w kodzie prawie identyczny jak wyżej, jedynie zmieniony operator:
const saveLocation = (location) => {
return of(location).pipe(delay(500));
};
const click$ = fromEvent(document, 'click');
let counter = 0;
click$
.pipe(
mergeMap((e: MouseEvent) => {
return saveLocation({
timestamp: Date.now(),
counter: counter++,
});
})
)
.subscribe((r) => console.log('Saved!', r));
Przykład użycia mergeMap()
na stackblitz.
Wynik w konsoli:

Jak widać każda subskrypcja została wykonana.
Podsumowanie
Różnice pomiędzy wspomnianymi operatorami nie są zbyt wielkie ale warto je znać aby w prawidłowy sposób korzystać z nich w trakcie kodowania. Dla chętnych pozostawiam fajny wykres, które być może jeszcze bardziej rozjaśni ten temat. Dziękuję za uwagę i do następnego wpisu!