注: 学习程墨老师《深入浅出RxJS》的笔记
任何一种 Reactive Extension 的实现,都包含一个操作符的集合。操作符其实就是解决某个具体应用问题的模式。
为什么要有操作符
一个操作符是返回一个Observable对象的函数。
const result$ = source$.filter(x => x * 2 === 0).map(x => x * 2);
result$.subscribe(console.log);
在RxJS的世界中,filter 和 map 这样的函数就是操作符,每个操作符提供的只是一些通用的简单功能,但是通过链式调用,这些小功能可以组合在一起,用来解决复杂的问题。
操作符分类
RxJS v5版本自带60做个操作符,按照功能分类,操作符可以分为:
- 创建类(creation)
- 转化类 (transformation)
- 过滤类 (filtering)
- 合并类(combination)
- 多播类(multicasing)
- 错误处理类(error Handling)
- 辅助工具类(utility)
- 条件分支类(conditional & boolean)
- 数学和合计类(mathmatial & aggregate)
静态和实例分类
按照形式分类,也就是操作符的实现函数和Observable类的关系。
- 静态操作符,操作符是Obervable类的静态函数
- 实例操作符,前提就是要有一个创建好的Observable对象,作为Observable的实例函数
// 静态操作符
Observable.of
// 实例操作符
Observable.prototype.map
如何实现操作符
每个操作符都是一个函数,不管实现什么功能,都必须考虑下面这些功能要点:
- 返回一个全新的Observable 对象
- 对上游和下游的订阅及退订处理
- 处理异常情况
- 及时释放资源,有些和浏览器资源打交道的操作符,或者有些和WebSocket资源关联,一定要在退订的时候去掉挂在DOM上的这些事件处理函数,释放WebSocket资源
手动实现map操作符
版本1:
function map(project){
// 1.返回一个全新的Observable对象
return new Observable((observer)=> {
const sub = this.subscribe({
next: value => {
// 3.处理异常情况
try {
observer.next(project(value))
} catch (err) {
observer.error(err);
}
},
error: err => observer.error(err),
complete: () => observer.complete(),
});
// 2.订阅和退订处理
return {
unsubscribe: () => {
sub.unsubscribe();
}
}
});
}
this代表的就是上游的Observable对象,箭头函数中的this直接绑定于定义函数环境下的this,而不是执行时指定的this。
版本2:
需要把map和Observable 关联起来,可以使用打补丁方法,如下
Observable.prototype.map = (project) => {
}
但是有时候我们并不希望一个操作符影响所有的Observable对象,我们只想在某些代码文件中使用,自定义的ma方法把RxJS自带的map覆盖了。
为了解决这个问题,我们自定义的操作符只对指定的Observable对象可用,这时就可以使用bind,如下
const result$ = map.bind(source$)(x => x * 2);
使用bind 的用法有个缺点,就是上游Observable只能作为操作符函数的参数,这样链式没法用了,比如想要连续使用两个map:
const result$ = map.bind( map.bind(source$)(x => x * 2) )(x => x + 1);
为了克服这个缺点,使用“绑定函数符”,绑定操作符以两个冒号形式存在,运行的时候运行绑定操作符后面的函数,但是保证函数运行时this是绑定操作符前面的对象。
const result$ = source$::map(x => x * 2)::map(x => x +1);
使用lift函数,lift是Observable的实例函数,它会返回一个新的Observable对象
版本3:
使用obs$,替换掉了this,因为直接使用this的函数不是纯函数
function map(project){
return function(obs$){
// 1.返回一个全新的Observable对象
return new Observable((observer)=> {
const sub = obs$.subscribe({
next: value => {
// 3.处理异常情况
try {
observer.next(project(value))
} catch (err) {
observer.error(err);
}
},
error: err => observer.error(err),
complete: () => observer.complete(),
});
// 2.订阅和退订处理
return {
unsubscribe: () => {
sub.unsubscribe();
}
}
});
}
}
要使用map就有借用let,let的作用是把map函数引入到链式调用之中,let起到连接上游下游作用,真正的工作完全由函数参数map来执行。
const result$ = source$.let(map(x => x * 2));
![](https://img.haomeiwen.com/i11094921/896aa0716060f993.png)
lettable 和 pipeable
要使用map就要借助let这个操作符的力量,能够被let当做参数来使用,就叫做lettable。
在RxJS v5中引入lettable操作符之后依然保留打补丁和call方法的操作符模块,完全是为了向后兼容,长远趋势lettable操作符是方向。
pipe是Observable自带一个新的操作符,具备let的功能,使用pipe 无需像使用let一样导入模块,任何Observable对象都支持pipe。pipe还有管道功能,可以把多个lettable操作符串联起来,形成数据管道。
const source$ = of(1, 2, 3);
const result$ = source$.pipe(
filter(x => x % 2 === 0),
map(x => x * 2),
);
result$ .subscribe(console.log);
网友评论