I am trying to better understand mergemap by recreating a very simple example and it is not behaving as I expected from my understanding of the official description.
In this example each successive document click outputs a single result (i.e. the output of the "of" observable, which is behaviour I would have expected from switchmap. My understanding of mergemap is that it will merge the results of multiple inner observables which does not appear to be the case here.
To examine the lifecycle of the observable I included the verbose version of the subscribe() function so I could see if complete() is called, but it isn't, so I expected the results of multiple of observerables to accumulate with successive document click and be presented in the output on each click. However what happens is a single new observable result is created each time. Why does each successive document click only emit one observable stream, and discard the previous one. Isnt this the behaviour of switchmap not mergemap?
fromEvent(document, 'click')
.pipe(mergeMap(() => of(Date.now())))
.subscribe({
next(x) {
console.log('value ', x);
},
complete() {
console.log('done');
},
});
CodePudding user response:
In this example each successive document click outputs a single result (i.e. the output of the "of" observable, which is behavior I would have expected from switchmap.)
In this example, switchMap
and mergeMap
have the same behavior.
Here's some code you can play around with to see where the two differ. Try this with both mergeMap
, switchMap
, and hey, why not try concatMap
too?.
// Lets pretend we're grabbing the date from a server.
// The server is slow, so this takes 3 seconds
function getDate(): Observable<number> {
return timer(3000).pipe(
map(_ => Date.now())
);
}
fromEvent(document, 'click').pipe(
take(5),
mergeMap(getDate)
).subscribe({
next: x => console.log('value ', x),
complete: () => console.log('done')
});
The difference:
You'll notice how mergeMap keeps every incoming 'click' from the document. If you 'click' twice, there will be two calls to getDate
and both calls will be kept active at the same time. 3 seconds later the first call will complete and emit a number and then some moments later the second call will complete and emit a number.
Once you've clicked 5 times and all the resulting calls to getDate
complete, you'll see your stream is done.
Try this with switchMap
and you'll notice that if you click more than once is a 3 second interval, the oldest click is dropped in favor of the newest one. switchMap
will only allow a single inner observable (call to getDate) to be active at a time, so it cancels old ones and switches over to the new ones.
This all becomes more interesting when dealing with observables that emit more than once.
A quick note:
the merge in mergeMap
doesn't mean "merge the items these streams emit." It means "merge these streams".