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 的影响。
RxJS 系列 – Custom Operator的更多相关文章
- [RxJS] Error handling operator: catch
Most of the common RxJS operators are about transformation, combination or filtering, but this lesso ...
- [转]VS Code 扩展 Angular 6 Snippets - TypeScript, Html, Angular Material, ngRx, RxJS & Flex Layout
本文转自:https://marketplace.visualstudio.com/items?itemName=Mikael.Angular-BeastCode VSCode Angular Typ ...
- [RxJS] Learn How To Use RxJS 5.5 Beta 2
The main changes is about how you import rxjs opreators from now on. And introduce lettable opreator ...
- RxJS——调度器(Scheduler)
调度器 什么是调度器?调度器是当开始订阅时,控制通知推送的.它由三个部分组成. 调度是数据结构.它知道怎样在优先级或其他标准去存储和排队运行的任务 调度器是一个执行上下文.它表示任务在何时何地执行(例 ...
- C++复制对象时勿忘每一部分
现看这样一个程序: void logCall(const string& funcname) //标记记录 { cout <<funcname <<endl; } cl ...
- Flink - DataStream
先看例子, final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); D ...
- 重载new delete操作符是怎么调用的
自定义的new操作符是怎么对英语new 一个对象的?自定义的delete操作符什么情况下得到调用?new一个对象时出现异常需要我操心内存泄露吗?下面的一个例子帮我们解开所有的疑惑. 1. 调用规则 ...
- 算法竞赛向 C++ Standard Library 使用速查
因网络上 STL 教程大多零散且缺乏严谨性,本文对算法竞赛所需 C++ Standard Library 做了一个较为全面的总结. 全文主要参考以下文档: Containers library - c ...
- [RxJS] Create a Reusable Operator from Scratch in RxJS
With knowledge of extending Subscriber and using source.lift to connect a source to a subscriber, yo ...
- [RxJS] Creation operator: of()
RxJS is a lot about the so-called "operators". We will learn most of the important operato ...
随机推荐
- 2024 年 Visual Studio 实用插件集合
前言 在软件开发领域,选择正确的工具可以极大地提升开发效率和质量. Visual Studio作为微软推出的强大集成开发环境(IDE),通过安装合适的插件,可以进一步增强其功能,满足开发者多样化的需求 ...
- 全网最适合入门的面向对象编程教程:13 类和对象的Python实现-可视化阅读代码神器Sourcetrail的安装使用
全网最适合入门的面向对象编程教程:13 类和对象的 Python 实现-可视化阅读代码神器 Sourcetrail 的安装使用 摘要: 本文主要介绍了可视化阅读代码神器Sourcetrail的安装与使 ...
- suffix-icon属性隐藏el-select下拉框右边的下拉图标
<el-form-item label="入库类型" prop="mt_type"> <el-select v-model="for ...
- oeasy教您玩转vim - 66 - # 比较修改模式 vimdiff
vimdiff 回忆上次 上次有三种批量替换,分别是 :windo :bufdo :argdo 执行的{cmd}可以用|按顺序增加 update 自动更新 :set autowrite 自动写入 ...
- [rCore学习笔记 07]移除标准库依赖
改造Rust hello world 移除println!宏 rustc添加对裸机的支持 rustup target add riscv64gc-unknown-none-elf detail rus ...
- 滑块解锁-scratch编程作品
程序说明: <滑块解锁>是一款基于Scratch平台制作的益智类小游戏.游戏中存在多个黄色滑块阻挡红色滑块通往出口的路径.玩家需要通过逻辑思考和精确操作,滑动黄色滑块以开辟道路,使红色滑块 ...
- Jmeter计数器
计数器(Counter)配置起点.最大值和增量,计数器将从开始循环到最大值,然后从头开始,继续这样直到测试结束 1.计数器 是可以根据线程计数的.组件路径[线程组->配置元件->计数器] ...
- 【WSDL】03 使用注解自定义服务信息
对原来的自定义WebService设置注解: package cn.cloud9.jax_ws.server.intf; import javax.jws.WebMethod; import java ...
- 【Uni-App】关于获取手机系统信息的项目实践
原因是这里APP下载方式的问题 安卓 和 IOS都可以写A标签跳转访问附件资源 但是甲方对这种下载方式并8满意[安卓行 苹果8行, 苹果行,安卓又8行] 通过 uni.getSystemInfo来判断 ...
- 【Scala】04 对象特性Part1
1.声明式包管理: 一个Scala文件可以声明N个包 包的意义和Java的包管理是一样的 同样也需要import导入资源声明 package pkgA { import com.oracle.nio. ...