Below is 2 snippets one with map
, and second one with switchMap
.
The working of map
is understandable:
of('foo', 'bar')
.pipe(map((val) => sanitizer(val)))
.subscribe((val) => console.log('value:', val));
function sanitizer(val: string) {
return val;
}
Output:
value: foo
value: bar
Now when using switchMap
, only the last value is outputting. Why is that?
My assumption was that map
is for sync operations and switchMap
is for async operations (returning observables/promises).
of('foo', 'bar')
.pipe(switchMap((val) => sanitizer(val)))
.subscribe((val) => console.log('value:', val));
async function sanitizer(val: string) {
return val;
}
Output:
value: bar
Here is stackblitz: https://stackblitz.com/edit/rxjs-acjgon?file=index.ts
3
Answers
switchMap
cancels the previous observable (switch to the new one), when a new values comes in, if you want to preserve the order then useconcatMap
– this will first resolve the first observable, then resolve the second! (order is preserved) (Special property of concatMap)of
immediately emits one after another, so the first does not get resolved.From the RxJS docs on
switchMap
:Remember that RxJS implements a push-based model. When
switchMap
receives a value, it begins processing it immediately. If a new value arrives during processing,switchMap
will abandon the currentObservable
orPromise
and switch to the new one.This behavior is especially useful in scenarios with frequent event updates, such as typing in a search box where only the latest input should fetch results:
However, for your case where each input must be addressed sequentially,
concatMap
is more appropriate as it processes values one after the other without interruption.Hope this helps!
Because of emits synchronously, and switchMap unsubscribe current inner observable at the moment it receives a new emission from the outer one.
Being those two emissions synchronous, it’s like it receives them "together", then discarding the first one and using just the second for its projection function.