为何switchMap操作符搭配Promise仅发出最后一个值?Observable则正常输出
为什么switchMap配合Observable和Promise行为不同?
哈哈,这个问题我刚学RxJS的时候也踩过坑!本质是Observable和Promise的核心特性差异,再加上switchMap的逻辑导致的,我给你拆解清楚~
先看两个示例代码
先上你提到的两种场景的代码,对比更直观:
Observable版本(符合预期输出所有值)
import { of } from 'rxjs'; import { switchMap } from 'rxjs/operators'; of(1, 2, 3).pipe( switchMap(num => of(`处理后: ${num}`)) ).subscribe(val => console.log(val)); // 输出结果: // 处理后: 1 // 处理后: 2 // 处理后: 3
Promise版本(只输出最后一个值)
import { of } from 'rxjs'; import { switchMap } from 'rxjs/operators'; of(1, 2, 3).pipe( switchMap(num => new Promise(resolve => { // 模拟异步操作 setTimeout(() => resolve(`处理后: ${num}`), 100); })) ).subscribe(val => console.log(val)); // 输出结果: // 处理后: 3
核心原因拆解
Observable vs Promise的本质差异
- Observable是多值流:可以连续发射多个值,直到完成或出错。
- Promise是单值容器:一旦调用
resolve或reject,就彻底完成了,不会再产生任何新值。
switchMap的核心逻辑
switchMap的作用是:每当源Observable发射一个新值,就立刻取消之前内部流(Observable/Promise)的订阅/执行,然后订阅新的内部流。- 当内部是Observable时:
of(...)是同步发射值的,源Observable发射1后,内部的of('处理后:1')瞬间就把值发射出去了,switchMap还没来得及处理源的下一个值(2),这个内部流就已经完成了。所以每个值都能被正常输出。 - 当内部是异步Promise时:源Observable会快速把1、2、3都发射出来。发射2的时候,switchMap会直接忽略第一个Promise的后续结果;发射3的时候,又会忽略第二个Promise的结果。最后只有第三个Promise的resolve结果会被订阅到,所以只输出最后一个值。
- 当内部是Observable时:
特殊情况:同步Promise
如果你的Promise是同步的(比如直接Promise.resolve(...)),那结果会和Observable一致:
of(1, 2, 3).pipe( switchMap(num => Promise.resolve(`处理后: ${num}`)) ).subscribe(val => console.log(val)); // 输出:处理后:1、处理后:2、处理后:3
因为同步Promise会立刻resolve,switchMap还没切换到下一个源值,当前的结果已经被发射了,不会被取消。
如何让Promise版本输出所有值?
如果你的需求是保留所有异步Promise的结果,不要取消之前的执行,那应该用mergeMap代替switchMap:
import { of } from 'rxjs'; import { mergeMap } from 'rxjs/operators'; of(1, 2, 3).pipe( mergeMap(num => new Promise(resolve => { setTimeout(() => resolve(`处理后: ${num}`), 100); })) ).subscribe(val => console.log(val)); // 输出:处理后:1、处理后:2、处理后:3(如果延迟时间不同,顺序可能变化)
mergeMap会并行处理所有内部流,不会取消之前的执行,所以所有Promise的结果都会被输出。
内容的提问来源于stack exchange,提问作者Martin
相关产品推荐
相关产品推荐

