为何传入恒等函数时RxJS的mergeMap会执行扁平化操作?
RxJS mergeMap 行为差异解析
核心逻辑:mergeMap 的 Observable 转换规则
mergeMap 的核心是将投影函数的返回值转换为 Observable,再把这个 Observable 发射的内容扁平化到下游流中。不同类型的返回值,RxJS 会采用不同的转换逻辑:
1. 返回数组时:自动拆分为单个元素
RxJS 会把数组识别为「类 Observable 对象」,内部等同于调用 from(数组) —— 这会将数组的每个元素依次发射出去。
对应你的第一段代码:
of(['click', 'tap']) .pipe( mergeMap(_ => _), // 投影函数直接返回数组['click', 'tap'] tap(console.log) // 依次接收'click'、'tap',触发两次 ) .subscribe();
这里 mergeMap(_ => _) 和 mergeMap(val => from(val)) 效果完全一致,数组被拆分为单个元素,所以下游会收到两次值。
2. 返回 Promise 时:仅发射完整的 Promise 结果
Promise 的特性是一次性返回完整结果,哪怕你用 Promise.resolve(数组),它也会把整个数组当作单一值返回。RxJS 将 Promise 转换为 Observable 后,这个 Observable 只会发射一次,值就是 Promise resolve 的完整数组。
对应你的第二段代码:
of(['click', 'tap']) .pipe( mergeMap(_ => Promise.resolve(_)), // 返回的Promise将整个数组作为单一结果resolve tap(console.log) // 仅接收一次完整数组['click', 'tap'] ) .subscribe();
因此下游只会触发一次 tap 回调。
扩展:让 Promise 场景也实现扁平化
如果希望在返回 Promise 的场景下也拆分数组元素,需要手动将 Promise 返回的数组转换为 Observable:
of(['click', 'tap']) .pipe( mergeMap(_ => Promise.resolve(_).then(arr => from(arr))), tap(console.log) // 同样依次接收'click'、'tap' ) .subscribe();
内容的提问来源于stack exchange,提问作者Thodoris
相关产品推荐
相关产品推荐

