rxjs拥有大量的操作符可以说基本涵括日常使用的方方面面, 但总有一天会有没有符合要求的操作符的一天, 或者, 即使有, 但我们却没有找到, 毕竟已经存在的操作符已经很多了, 说不定会越来越多, 这时就需要我们来自定义操作符了。
本文针对 rxjs6 ,以前的版本可以查看 这篇文章。
为Operator添加操作符
在5.5版本, rxjs增加了pipe操作符, 在那之后, 自定义操作符的方式就很简单了, 基本就是实现一个函数, 官方文档中有如下描述:
基本上来说,pipeable 操作符可以是任何函数,但是它需要返回签名为的函数。
(source: Observable ) => Observable
现在Observable
中有一个内置的pipe
方法 (Observable.prototype.pipe
),它可以用类似于之前的链式调用的方式来组合操作符
所以我们只需要定义一个函数, 他的返回值签名是
就可以了。
在使用一个例子开始以前,让我们看看编写操作符的注意事项
- 操作符的返回值必须是Observable类型,没有第二种可能。
- 一定要管理好subscription,这样订阅生产的资源才能及时被释放。
- 处理好异常,因为你无法保证用户传进来的逻辑永远都可以正确运行。
- 在合适的时间,处理好其它你需要释放的资源,例如流结时,或抛出错误时。
接下来让我们用一个简单的例子来实现以下
一个简单的例子
假如我们需要一个对数字进行平方的操作符:
square = () => {
return source => {
return source.pipe(map((value: number) => value * value));
};
}
他的入参为空, 返回的函数的行参source就是即将被传入的observable,
然后我们就可以在,pipe()
中调用了
test() {
const obs = of(1, 2, 3);
// 1, 4, 9
obs.pipe(square()).subscribe((value) => console.log(value));
}
一个简单的操作符就完成了,但,是不是感觉还少了些什么,对,要是传入进来的不是一个数字呢,那时用户会收到一个NaN(Not a Number)
, 所以,我们还需要给他判断一下并报错
const square = () => source => source
.pipe(map((value: number) => {
// 判断传入的值是否为数字
if (value && !isNaN(value)) {
return value * value;
}
throw Error('收到的数据不是数值类型');
}),
catchError(err => of(err.toString())));
lift()
自定义操作符除了可以通过pipe()
进行,还有很多地方提到了lift()
这个方法, 并且很多地方都把 lift()
和pipe()
作为对比,所以又去学习了一下lift()
创建一个新的Observable,以该Observable作为源,并将传递的运算符定义为新Observable的运算符。
它和pipe()
的对比可以查看这篇文章
简单的说
lift()创建一个新的可观察对象,但pipe()没有。pipe()遵循函数式编程范式,lift()是面向对象的。
(后面这部分感觉理解的还不是很到位就不翻译了)
- pipe's operator function maps an Observable to an Observable
- lift's operator function maps an Observer to an Observer
This is just another way to represent the idea of either:
- building an Observable chain down from the source to the sink
- or building an Observer chain up from the sink to the source
如何使用lift()
rxjs
中lift()
如何使用呢, ,下面是一个简单的例子,改造后的square()
:
class Square implements Operator {
call(subscriber: Subscriber, source: Observable): void {
source.subscribe(value => {
if (value && !isNaN(value)) {
subscriber.next(value * value);
}
throw Error('收到的数据不是数值类型');
},
error => console.log(error));
}
}
使用
test() {
const obs = of(123);
obs.lift(new Square()).subscribe((value) => console.log(value)); // 1, 4, 9
}
上面只是一个简单的例子,若想通过lift()
编写操作符,可以直接参考那些操作符的源码, lift()
在源码中有大量的使用。
总结
写完以后能明显的感觉到这篇文章还有很大的改进空间,本来还想更细致探讨一下原理性的东西的,但是那一大堆花里胡哨的函数签名看的自己直发晕,而且现在汇报时间就要到了,还是算了,等自己水平再提升一些了再来看吧。
参考文章
Rxjs-自定义操作符
官方文档
What is the difference between Observable.lift and Observable.pipe in rxjs?