第3章 操作符基础

2021-07-18  本文已影响0人  我是小布丁

注: 学习程墨老师《深入浅出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做个操作符,按照功能分类,操作符可以分为:

静态和实例分类

按照形式分类,也就是操作符的实现函数和Observable类的关系。

// 静态操作符
Observable.of

// 实例操作符
Observable.prototype.map

如何实现操作符

每个操作符都是一个函数,不管实现什么功能,都必须考虑下面这些功能要点:

手动实现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));
image.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);
上一篇 下一篇

猜你喜欢

热点阅读