订阅操作符返回的Observable时,源Observable为何会发射值?
为什么订阅
mapped$会触发origin$发射值? 这是个非常好的问题,核心要搞懂两个关键点:Cold Observable的特性,以及RxJS操作符的本质逻辑~
1. Cold Observable的核心特性
Cold Observable(冷Observable)的核心特点是:只有被订阅时才会启动数据发射逻辑,而且每一次订阅都会从头生成完整的数据流。你定义的origin$ = Rx.Observable.from([1,2,3,4])就是典型的Cold Observable——如果没有任何订阅动作,它完全不会产生任何数据。
2. RxJS操作符(比如map)的本质
当你调用origin$.map(val => val+1)返回mapped$时,这个mapped$并不是一个独立生成数据的全新Observable,它更像是一个**“中间代理”**:
- 它自己不会凭空产生数据,所有数据都依赖于源Observable(也就是
origin$); - 当
mapped$被订阅时,它会在内部自动发起对origin$的订阅,把源Observable发射的每个值拿过来,经过map的转换逻辑(这里是val+1),再传递给mapped$的订阅者。
用你的代码拆解完整流程
咱们一步步捋你这段代码的执行顺序:
const origin$ = Rx.Observable.from([1,2,3,4]); const mapped$ = origin$.map(val => val+1); mapped$.subscribe(console.log);
- 第一行:创建了
origin$这个Cold Observable,但此时没有订阅,它啥也不会做; - 第二行:调用
map操作符得到mapped$,这时候mapped$只是保存了“要订阅origin$、转换每个值”的逻辑,还没实际执行; - 第三行:订阅
mapped$——这是关键触发点:mapped$收到订阅请求后,立刻在内部调用origin$.subscribe(...)(这个内部订阅的回调就是处理map转换的逻辑);- 此时
origin$终于被订阅,开始发射1,2,3,4; - 每个值被
origin$发射后,先经过map的转换变成2,3,4,5,再传给mapped$的订阅者console.log,最终打印出来。
简单模拟map的内部逻辑
如果你想更直观理解,可以把map的工作逻辑简化成这样(伪代码):
function map(source$, transformFn) { return new Observable(observer => { // 当新Observable被订阅时,内部自动订阅源Observable const subscription = source$.subscribe({ next: val => observer.next(transformFn(val)), error: err => observer.error(err), complete: () => observer.complete() }); return subscription; }); }
看,新的Observable在被订阅时,必然会去订阅源Observable——这就是为什么订阅mapped$会触发origin$开始发射值的核心原因。
总结一下:RxJS的操作符链式调用,本质是构建了一条订阅链——最下游的订阅会触发上游所有Observable的订阅,直到源头的Cold Observable启动数据发射。
内容的提问来源于stack exchange,提问作者user8041768
相关产品推荐
相关产品推荐

