RxJS · 从 Observable 标准契约,到它解决的那些问题
RxJS 常被当成「一大堆 operator」来记,内核却只有一个标准契约:Observable,一个可以脱离库、用十几行就手写出来的接口。subscribe(observer) 触发一个 producer,producer 通过 observer.next / error / complete 把值推出去,并返回一个 teardown 作为 Subscription 供取消。TC39 的 Observable proposal 与 WICG 的 DOM Observable 提案(EventTarget.when())要标准化的就是这个形状 —— 后者仍是实验特性,仅 Chromium 135+(2025-04)落地(核对于 2026-08)。
本系列从这个契约本身出发: 先把它放进 singular/plural × pull/push 的标准坐标系里,看清它和 function / Iterator / Promise 的分工; 再依次拆 创建 → 变换 (operator) → 组合 (高阶 flatten) → 共享 (hot/cold); 最后落到工程里真正要解决的问题 —— 取消陈旧请求、防抖 autocomplete、拖拽、重试。每页都用 marble diagram 单步观察流随时间的演化。
契约:十几行手写一个 Observable
从零手写 Observable:subscribe 调用 producer,producer 用 observer 上的三个方法推值,返回的 teardown 就是 Subscription。
坐标系:function / Iterator / Promise / Observable
把四种取值方式放进「单值 / 多值 × 拉 / 推」的 2×2 网格:单值加拉是 function,多值加拉是 Iterator,单值加推是 Promise,多值加推是 Observable。每格用能跑的代码演示各自的取值接口。
创建:把任何东西变成一条流
五个 creation function 把值、数组、Promise、定时器与 DOM 事件包成同一种 Observable。其中四个是 cold 的,fromEvent 惰性但 hot。
变换:pipe 把 operator 串成管道
operator 是纯函数,吃一个 Observable 返回一个新的 Observable,从不改动上游;pipe(a, b, c) 只是函数组合。逐值看五个 operator 如何改写、丢弃或截断 marble。
展平:一个值映射成一条流,四种策略
map 的结果本身是 Observable 时得到高阶 Observable,需展平成一条流。内层重叠时保留谁,分出四种策略:全留、排队、留新、留旧。
冷与热:各跑一遍,还是共享一次执行
cold Observable 每个订阅者各触发一次独立执行;hot 流的值独立于订阅产生,多个订阅者共享同一次执行,晚订阅者错过之前的值。share 与 multicast 如何把 cold 转 hot。
落地:这些问题,用流怎么解决
把前面的契约与 operator 对上真实痛点:autocomplete 的抖动与请求竞态、拖拽的三事件组合、失败后按退避重订阅。末尾一张「问题到 operator」的速查表。
一句话串起来
Observable —— 推送式、惰性、可取消的多值序列 (见 契约),它在 pull/push × 单值/多值 坐标系里正好补上 Promise 缺的那格 (见 坐标系)。有了契约就能把任何东西创建成 cold 流 (见 创建),用 pipe 里的纯函数 operator 变换 (见 变换);当值映射出的又是流,就用四种 flatten 组合 (见 高阶),用 Subject / share 决定是否共享执行 (见 冷与热)。这一切最终是为了优雅解决工程里的竞态、防抖、取消、重试 (见 落地)。顺着标准与源头读下去
官方文档 / 教程
- RxJS · Observable 指南 rxjs.dev 官方对 Observable / Observer / Subscription / Subject / operator 的权威说明,marble 与代码对照。
- Learn RxJS learnrxjs.io 按 operator 分类的速查与配方,每条附可运行示例;查「该用哪个 operator」的好去处。
- RxMarbles rxmarbles.com 可交互 marble diagram:拖动源 marble 实时看各 operator 的输出,本系列可视化的灵感来源。
标准接口的源头
-
TC39 · Observable proposal
github.com
把 Observable 纳入 ECMAScript 的提案,定义了
subscribe/ Observer / Subscription 的最小契约。 -
WICG · Observable (DOM) 提案
github.com
把 Observable 引入 DOM 的提案本体:
EventTarget.when()直接返回事件的 Observable,相当于原生的fromEvent。仅 Chromium 系落地。 - MDN · Streams API developer.mozilla.org 对照另一套「流」抽象:ReadableStream 是 pull-based + backpressure,与 Observable 的 push 模型形成互补。