为rxjs添加自定义操做符

rxjs拥有大量的操做符能够说基本涵括平常使用的方方面面, 但总有一天会有没有符合要求的操做符的一天, 或者, 即便有, 但咱们却没有找到, 毕竟已经存在的操做符已经不少了, 说不定会愈来愈多, 这时就须要咱们来自定义操做符了。html

本文针对 rxjs6 ,之前的版本能够查看 这篇文章

为Operator添加操做符

在5.5版本, rxjs增长了pipe操做符, 在那以后, 自定义操做符的方式就很简单了, 基本就是实现一个函数, 官方文档中有以下描述:编程

基本上来讲,pipeable 操做符能够是任何函数,可是它须要返回签名为 <T, R>(source: Observable<T>) => Observable<R>的函数。
如今 Observable中有一个内置的 pipe方法 ( Observable.prototype.pipe),它能够用相似于以前的链式调用的方式来组合操做符

因此咱们只须要定义一个函数, 他的返回值签名是<T, R>(source: Observable<T>) => Observable<R>就能够了。segmentfault

在使用一个例子开始之前,让咱们看看编写操做符的注意事项ide

  • 操做符的返回值必须是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), 因此,咱们还须要给他判断一下并报错ui

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()
image.pngidea

建立一个新的Observable,以该Observable做为源,并将传递的运算符定义为新Observable的运算符。

它和pipe()的对比能够查看这篇文章
简单的说spa

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()

rxjslift()如何使用呢, ,下面是一个简单的例子,改造后的square():

class Square implements Operator<number, number> {
  call(subscriber: Subscriber<number>, source: Observable<number>): 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?

相关文章
相关标签/搜索