RxSwift中map与flatMap输出差异原因及算子区别咨询
为什么RxSwift中map与flatMap在这段代码里输出不同?
核心差异根源
两段代码的输出差异,本质是map和flatMap的算子特性不同,再结合take(1)的订阅终止逻辑、observe(on:)的异步调度共同导致的。
先明确两个算子的本质区别
- map:纯元素转换,输入一个元素,同步输出一个新元素,不会改变原序列的事件流结构。上游的
completed事件会直接传递给下游。 - flatMap:序列转换,输入一个元素,输出一个新的Observable,它会订阅这个内部Observable,并将其所有事件(
next/completed)转发给下游。只有当内部Observable完成,且上游序列也完成时,flatMap返回的序列才会触发completed。
逐段分析执行流程
test1(使用map)的执行逻辑
- 初始时
combineLatest发射组合值(true, 0),通过filter触发打印,debug输出订阅和事件信息。 observe(on: MainScheduler.asyncInstance)将事件切换到主线程异步执行。take(1)收到第一个元素后,会立即执行三个动作:- 通过
map转换出0,触发do(onNext)打印---next value 0; - 向下游发送
completed事件,触发do(onCompleted)执行sb2.accept(12); - 立即取消对上游序列(
combineLatest链)的订阅。
- 通过
- 此时
sb2的新值12无法触发combineLatest,因为上游订阅已经被终止,所以不会再产生filter和debug的打印。
test2(使用flatMap)的执行逻辑
- 前两步和test1完全一致:
combineLatest发射(true, 0),过filter、debug,切换到主线程异步。 take(1)收到元素后,传递给flatMap,flatMap创建Observable.just(0)并订阅它。take(1)向上游发送取消订阅的信号,但由于observe(on:)的异步调度,这个取消信号的传递是延迟的。- 内部的
Observable.just(0)同步发射元素,触发do(onNext)打印---next value 0,随后内部Observable完成。 - 只有当内部Observable完成后,
flatMap才会向下游发送completed事件,触发do(onCompleted)执行sb2.accept(12)。 - 此时上游的
combineLatest还未处理完取消订阅的信号,所以会收到sb2的新值12,再次触发filter和debug的打印。
总结输出差异
- test1的输出只会有初始事件的打印,修改
sb2后不会产生新事件:---filter---------- ---debug: subscribed ---debug: Event next((true, 0)) ---next value 0 ---send next - test2的输出会多一次
sb2修改后的事件打印:---filter---------- ---debug: subscribed ---debug: Event next((true, 0)) ---next value 0 ---send next ---filter---------- ---debug: Event next((true, 12))
内容的提问来源于stack exchange,提问作者Yorn
相关产品推荐
相关产品推荐

