RxJS 系列 – Custom Operator
前言
虽然 RxJS 提供了非常多的 Operators. 但依然会有不够用的时候. 这时就可以自定义 Operator 了.
Operator Is Just a Function Observable => Observable
Operator 只是一个函数.
timer(1000).pipe(obs => obs).subscribe();
它接收一个 Observable 返回一个 Observable.
Operator 都是放在管道 (pipe) 内的, 所以从源头 Observable 一直传递下去.
每一个 Operator 接收 upstream(上游) 的 Observable 并且返回一个 Observable (通常是新的一个) 给 downstream(下游).
每一个 Operator 就是对发布值的加工处理.
Standard Operator
source 源头
首先我们有个源头
const source = timer(1000);
每一秒发布一次
Upstream / Downstream Observable
接着搞一个 pipe 和 operator.
const source = timer(1000); source .pipe(upstreamObs => { console.log(upstreamObs === source); // true const downstreamObs = new Observable(); return downstreamObs; }) .subscribe(v => console.log(v));
可以看到 operator 函数接收的就是 upstream 的 Observable, 然后返回一个新的 Observable 到 downstream.
Connect Upstream and Downstream
downstream to upstream
当 downstream 被 subscribe, 我们 subscribe upstream
当 downstream 被 unsubscribe, 我们 unsubscribe upstream
const source = timer(1000); source .pipe(upstreamObs => { const downstreamObs = new Observable(subscriber => { // 当 downstream Observable 被订阅以后, 我们才订阅 upstream Observable const upstreamSub = upstreamObs.subscribe(); return () => { // 当 downstream 被退订以后, 我们也要退订 upstream Observable upstreamSub.unsubscribe(); }; }); return downstreamObs; }) .subscribe(v => console.log(v));
upstream to downstream
当接收到 upstream 发布时, 我们也发布到 downstream
const downstreamObs = new Observable(subscriber => { const upstreamSub = upstreamObs.subscribe({ next: upstreamValue => { const downStreamValue = upstreamValue + 'downstream value'; // decorate value for downstream subscriber.next(downStreamValue); // 发布到 downstream }, error: error => subscriber.error(error), // 转发去 downstream complete: () => subscriber.complete(), // 转发去 downstream }); return () => { upstreamSub.unsubscribe(); }; });
小结
从上面几招可以看出来, 主要就是 upstream 和 downstream 中间的关系.
如何订阅, 退订, 发布 value 等等. 上面只是给一个简单直观的例子. 真实场景中, upstream 和 downstream 发布时机, 往往是不一致的 (比如 upstream 发布 1 次后, downstream 可能发布多次)
Operator with Config
只要把 Operator 包装成工厂函数就可以支持 Config 了
function myOperator(config: { dependObs: Observable<unknown> }): OperatorFunction<number, string> { const { dependObs }= config; return upstreamObs => { const downstreamObs = new Observable<string>(subscriber => { // 订阅 depend const dependObsSub = dependObs.subscribe(() => console.log('do something')); const upstreamSub = upstreamObs.subscribe({ next: upstreamValue => { const downStreamValue = upstreamValue + 'downstream value'; // decorate value for downstream subscriber.next(downStreamValue); // 发布到 downstream }, error: error => subscriber.error(error), // 转发去 downstream complete: () => { // 释放 depend dependObsSub.unsubscribe(); subscriber.complete(); }, }); return () => { upstreamSub.unsubscribe(); // 释放 depend dependObsSub.unsubscribe(); }; }); return downstreamObs; }; } const source = timer(1000); const dependObs = new Subject(); source.pipe(myOperator({ dependObs })).subscribe(v => console.log(v));
一个 Factory 函数, 通过配置生产 Operator。
OperatorFunction 定义了 Operator 接口, 它是加入了泛型的 Observable => Observable.
如果 upstream 和 downstream 的类型是一样的话可以用它的简化版本 MonoTypeOperatorFunction<T>
Unsubscribe dependency stream
比如说像 takeUntil operator
const obs = timer(0, 1000); // 0..1..2..3..4..5 obs.pipe(takeUntil(timer(3000))).subscribe(v => console.log(v)); // 0..1..2
它内部会 subscribe timer$,timer$ 就是它的 dependency observable。
如果在还没有到 3 秒的时候,这个 observable 就被 unsubscribe 了,那 takeUntil operator 内部就要提前去 unsubscribe timer$。
同理,如果这个 observable 在还没有到 3 秒的时候,就被 error 或 complete 了,那 takeUntil operator 内部也需要提前去 unsubscribe timer$。
总之,我们在设计 operator 时,一定要顾虑到 upstream 的 error / complete 和 downstream 的 unsubscribe 对 dependency observable 的影响。