7

I have some trouble to understand this. When I use the switchMap operator with an Observable it emits all the values as expected:

Observable.from([1, 2, 3, 4, 5])
    .do(console.log)
    .switchMap(i => Observable.of('*' + i))
    .do(console.log)
    .subscribe();

Results:

1
*1
2
*2
3
*3
4
*4
5
*5

But when I replace the the Observable by a Promise I get a different behaviour:

Observable.from([1, 2, 3, 4, 5])
    .do(console.log)
    .switchMap(i => new Promise((resolve) => resolve('*' + i)))
    .do(console.log)
    .subscribe();

Results:

1
2
3
4
5
*5
Martin
  • 123
  • 9

2 Answers2

3

This works as expected. The unexpected behaviors as you said is because Observable.from and Observable.of are always strictly synchronous while new Promise necessarily doesn't (I'm not sure about the specification so maybe that's what Promise has to do in all browsers).

Anyway you can force Observable.from emit asynchronously by passing the async Scheduler.

import { Observable } from 'rxjs';
import { async } from 'rxjs/scheduler/async';

Observable.from([1, 2, 3, 4, 5], async)
    .do(console.log)
    .switchMap(i => new Promise((resolve) => resolve('*' + i)))
    .do(console.log)
    .subscribe();

Now every emission is in a new frame just like Promise and the output is as you expected.

See live demo (open console): https://stackblitz.com/edit/rxjs5-gfeqsn?file=index.ts

martin
  • 93,354
  • 25
  • 191
  • 226
  • This completely makes sense! But could you clarify why the fact of having emissions in separate frames behave this way? I would expect to have all emissions as output. (Or I probably don't understand the expected behaviour of switchMap.) Thanks. @martin – Martin Feb 17 '18 at 16:59
  • 1
    That's because `switchMap` receives `1` and subscribes to `new Promise()`. Then in the same frame it receives `2` and unsubscribes from the previous `Promise` and subscribes to the new one and so on. And only after `5` and its `Promise` the frame ends and JS evaluates another frame where only the last active `Promise` is resolved. – martin Feb 17 '18 at 17:52
0

Try mergeMap, maybe it is what you are looking for.

Rdey
  • 420
  • 6
  • 9