Operators (操作符)

尽管 RxJS 的根基是 Observable,但最有用的还是它的操作符。操作符是允许复杂的异步代码以声明式的方式进行轻松组合的基础代码单元。

什么是操作符?

操作符是 Observable 类型上的方法,比如 .map(...).filter(...).merge(...),等等。当操作符被调用时,它们不会改变已经存在的 Observable 实例。相反,它们返回一个新的 Observable ,它的 subscription 逻辑基于第一个 Observable 。

操作符是函数,它基于当前的 Observable 创建一个新的 Observable。这是一个无副作用的操作:前面的 Observable 保持不变。

操作符本质上是一个纯函数 (pure function),它接收一个 Observable 作为输入,并生成一个新的 Observable 作为输出。订阅输出 Observable 同样会订阅输入 Observable 。在下面的示例中,我们创建一个自定义操作符函数,它将从输入 Observable 接收的每个值都乘以10:

  1. function multiplyByTen(input) {
  2. var output = Rx.Observable.create(function subscribe(observer) {
  3. input.subscribe({
  4. next: (v) => observer.next(10 * v),
  5. error: (err) => observer.error(err),
  6. complete: () => observer.complete()
  7. });
  8. });
  9. return output;
  10. }
  11. var input = Rx.Observable.from([1, 2, 3, 4]);
  12. var output = multiplyByTen(input);
  13. output.subscribe(x => console.log(x));

输出:

  1. 10
  2. 20
  3. 30
  4. 40

注意,订阅 output 会导致 input Observable 也被订阅。我们称之为“操作符订阅链”。

实例操作符 vs. 静态操作符

什么是实例操作符? - 通常提到操作符时,我们指的是实例操作符,它是 Observable 实例上的方法。举例来说,如果上面的 multiplyByTen 是官方提供的实例操作符,它看起来大致是这个样子的:

  1. Rx.Observable.prototype.multiplyByTen = function multiplyByTen() {
  2. var input = this;
  3. return Rx.Observable.create(function subscribe(observer) {
  4. input.subscribe({
  5. next: (v) => observer.next(10 * v),
  6. error: (err) => observer.error(err),
  7. complete: () => observer.complete()
  8. });
  9. });
  10. }

实例运算符是使用 this 关键字来指代输入的 Observable 的函数。

注意,这里的 input Observable 不再是一个函数参数,它现在是 this 对象。下面是我们如何使用这样的实例运算符:

  1. var observable = Rx.Observable.from([1, 2, 3, 4]).multiplyByTen();
  2. observable.subscribe(x => console.log(x));

什么是静态操作符? - 除了实例操作符,还有静态操作符,它们是直接附加到 Observable 类上的。静态操作符在内部不使用 this 关键字,而是完全依赖于它的参数。

静态操作符是附加到 Observalbe 类上的纯函数,通常用来从头开始创建 Observalbe 。

最常用的静态操作符类型是所谓的创建操作符。它们只接收非 Observable 参数,比如数字,然后创建一个新的 Observable ,而不是将一个输入 Observable 转换为输出 Observable 。

一个典型的静态操作符例子就是 interval 函数。它接收一个数字(非 Observable)作为参数,并生产一个 Observable 作为输出:

  1. var observable = Rx.Observable.interval(1000 /* 毫秒数 */);

创建操作符的另一个例子就是 create,已经在前面的示例中广泛使用。点击这里查看所有静态操作符列表。

然而,有些静态操作符可能不同于简单的创建。一些组合操作符可能是静态的,比如 mergecombineLatestconcat,等等。这些作为静态运算符是有道理的,因为它们将多个 Observables 作为输入,而不仅仅是一个,例如:

  1. var observable1 = Rx.Observable.interval(1000);
  2. var observable2 = Rx.Observable.interval(400);
  3. var merged = Rx.Observable.merge(observable1, observable2);

Marble diagrams (弹珠图)

要解释操作符是如何工作的,文字描述通常是不足以描述清楚的。许多操作符都是跟时间相关的,它们可能会以不同的方式延迟(delay)、取样(sample)、节流(throttle)或去抖动值(debonce)。图表通常是更适合的工具。弹珠图是操作符运行方式的视觉表示,其中包含输入 Obserable(s) (输入可能是多个 Observable )、操作符及其参数和输出 Observable 。

在弹珠图中,时间流向右边,图描述了在 Observable 执行中值(“弹珠”)是如何发出的。

在下图中可以看到解剖过的弹珠图。

Operators (操作符) - 图1

在整个文档站中,我们广泛地使用弹珠图来解释操作符的工作方式。它们在其他环境中也可能非常有用,例如在白板上,甚至在我们的单元测试中(如 ASCII 图)。

选择操作符

操作符分类

操作符有着不同的用途,它们可作如下分类:创建、转换、过滤、组合、错误处理、工具,等等。在下面的列表中,你可以按分类组织好的所有操作符。

创建操作符

转换操作符

过滤操作符

组合操作符

多播操作符

错误处理操作符

工具操作符

条件和布尔操作符

数学和聚合操作符