13-11.【Combine】merge、combineLatest、zip 的区别和典型用法?

1 阅读3分钟

这三个操作符是 Combine 中处理多流聚合的核心工具。它们最本质的区别在于触发条件以及对数据配对的逻辑


1. Merge(合并)

本质:将多个相同类型的流“揉”成一个。

merge 不会对数据做任何处理,它只是简单地把多个 Publisher 的输出汇集到同一个管道里。

  • 触发机制:任何一个上游发出值,下游就立即收到该值。

  • 类型要求:所有上游 Publisher 的 OutputFailure 类型必须完全一致

  • 典型用法

    • 多来源更新:比如一个列表的数据可以来自“下拉刷新”、“点击按钮刷新”和“自动轮询”。这三个事件都可以 merge 在一起,触发同一个网络请求。
    • UI 事件汇总:将界面上多个按钮的点击流合并,执行统一的统计逻辑。

2. CombineLatest(最新组合)

本质:关注所有流的“当前状态”。

combineLatest 会保存每个上游发出的最后一个值。只要任何一个上游更新,它就会把所有流的最新值打包成一个元组(Tuple)发出来。

  • 触发机制

    1. 初始触发:必须等到所有上游都至少发过一次值后,下游才会开始工作。
    2. 后续触发:此后任何一个上游更新,下游都会收到一份“全家福”快照。
  • 典型用法

    • 表单验证(最经典) :只有当“账号”、“密码”和“验证码”三个输入框都填了,且其中任何一个变化时,才重新计算“登录按钮”是否可用。
    • 多维过滤:比如电商页面,同时根据“价格区间”、“分类”和“销量排序”三个筛选器的最新状态来请求搜索结果。

3. Zip(拉链配对)

本质:严格的一一对应。

zip 像拉链一样,必须左边一个齿和右边一个齿扣在一起。它会等待所有上游提供相同序号的值。

  • 触发机制:只有当所有上游都发出了“第 nn 个”值时,下游才会发出由这些第 nn 个值组成的元组。

  • 特性:它会“缓存”跑得快的流,等待跑得慢的流。如果一个流发了 10 个值,另一个只发了 1 个,下游只会收到 1 个组合值。

  • 典型用法

    • 并行异步任务同步:同时发起两个互不相关的 API 请求(比如用户信息和用户资产),只有当两个都返回成功时,才把它们组合在一起显示。
    • 数据比对:将“旧值流”和“新值流”通过偏移一位进行 zip,从而比较前后两个状态的差异。

4. 核心特性对比表

特性MergeCombineLatestZip
关注点时间先后状态快照序列配对
输出形式单个值(AABB元组(最新 AA + 最新 BB元组(第 nnAA + 第 nnBB
触发前提任一发出即触发所有流都发过至少一次值所有流都发出对应序号的值
类型限制类型必须完全一致类型可以不同类型可以不同
结束时机所有上游都结束所有上游都结束任一上游结束且无法配对

5. 防御式编程警示

  • CombineLatest 的“冷启动”延迟

    如果你的 combineLatest 关联了 5 个流,只要其中 1 个一直没发值,整个下游就会处于“静默”状态。这在调试时经常被误认为代码没跑通。

    • 对策:给那些可能延迟发值的流提供一个 .prepend(defaultValue) 初始值。
  • Zip 的内存隐患

    如果一个流产生的频率极高(如传感器数据),而另一个流极慢,zip 会在内存中缓存那个高频流产生的所有未配对数据。

    • 对策:避免将步调差异巨大的流进行 zip,或者给高频流加 bufferdrop

总结

  • 谁来都行?merge
  • 我要所有人的最新状态?combineLatest
  • 必须成双成对?zip