变换:pipe 把 operator 串成管道
contract 一页里,一条 Observable 只会把源头的值原样推给你。真正的表达力来自 operator:每个 operator 都是一个纯函数,吃一个上游 Observable、返回一个全新的 Observable,从不改动上游。pipe(a, b, c)
只是把这些纯函数组合起来,数据自上而下、逐节流过每一个 operator——上游不知道下游是谁,下游也拿不到上游的内部状态,只看得到流出来的 marble。
1 · 单个 operator:上游一条,下游一条
下面固定一条源流 source$(在 t=1..6 依次推 1,2,3,4,5,6,t=7 用 complete 封口)。换一个 operator,就用它把 source$ 变换成一条新的 result$。点「下一步」推进时间游标,同一时刻上下游一起点亮,直观看出每一颗 marble 是怎么被这一节改写、丢弃或改数的。source$ 那条轴自始至终不变——这就是不可变。
2 · 组合:pipe 三节串联,数据逐节变形
operator 是纯函数,组合它们就是函数组合。下面这条 pipe 把三节接在一起:先 filter 只留偶数,再 map 把值乘十,最后 take(2) 取够两个就 complete。四条时间轴并排——源 → filter 后 →
map 后 → take 后——一步步看同一颗值怎样被下一节接手、变形,或在 take 满员后连同后续一起被截断。
operator 是纯函数,流是不可变的。 每个 operator 只读上游、产出一条新流,绝不回头改上游——所以同一个 source$ 可以被多条不同的 pipe 各自消费,互不干扰,和数组的 map / filter 返回新数组是同一种思路。正因为 operator 只是「Observable →
Observable」的函数,pipe 才能像搭积木一样自由拼接。但当 map 的返回值本身又是一个 Observable(比如每个 id 去发一个请求),就会得到「流的流」,这时要靠 高阶 operator 把内层摊平。