Search code examples
promiserxjsobservablerxjs5switchmap

Why does switchMap operator only emit the last value when used with a promise?


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

Solution

  • 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