深入浅出 RxJS 之 辅助类操作符

2023-05-17 20:40:02 浏览数 (1)

| 功能需求 | 适用的操作符 | | 统计数据流中产生的所有数据个数 | count | | 获得数据流中最大或者最小的数据 | maxmin | | 对数据流中的数据进行规约操作 | reduce | | 判断是否所有数据满足某个条件 | every | | 找到第一个满足判定条件的数据 | findfindIndex | | 判断一个数据流是否不包含任何数据 | isEmpty | | 判断一个数据流为空就默认产生一个指定数据 | defaultIfEmpty |

# 数学类操作符

数学类操作符是体现数学计算功能的一类操作符,RxJS 自带的数学类操作符只有四个,分别是:

  • count
  • max
  • min
  • reduce

所有这些操作符都是实例操作符,还有一个共同特点,就是这些操作符必定会遍历上游 Observable 对象中吐出的所有数据才给下游传递数据,也就是说,它们只有在上游完结的时候,才给下游传递唯一数据。

# count:统计数据个数

代码语言:javascript复制
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/concat';
import 'rxjs/add/operator/count';

const source$ = Observable.of(1, 2, 3).concat(Observable.of(4, 5, 6));
const count$ = source$.count();

// 6

要想统计一个 Observable 对象中产生的所有数据个数,只能等到它结束。

# max 和 min :最大最小值

代码语言:javascript复制
const initialRelease$ = Observable.of(
  { name: 'RxJS', year: 2011 },
  { name: 'React', year: 2013 },
  { name: 'Redux', year: 2015 }
);
const min$ = initialRelease$.min((a, b) => a.year - b.year);

// { name: 'RxJS', year: 2011 }

# reduce:规约统计

reduce 的功能就是对一个集合中所有元素依次调用这个规约函数,这个规约函数可以返回一个“累积”的结果,然后这个“累积”的结果会作为参数和数据集合的下一个元素一起成为规约函数下次被调用的参数,如此遍历集合中所有的元素,因为规约函数可以任意定义,所以最后得到的“累积”结果也就完全可定制。

除了规约函数, reduce 还有一个可选参数 seed ,这是规约过程中“累计”的初始值,如果不指定 seed 参数,那么数据集合中的第一个数据就充当初始值,当然,这样第一个数据不会作为 current 参数调用规约函数,而是直接作为 accumulation 参数传递给规约函数的第一次调用。

代码语言:javascript复制
import 'rxjs/add/observable/range';
import 'rxjs/add/operator/reduce';

const source$ = Observable.range(1, 100);
const reduce$ = source$.reduce(
  (accumulation, current) => accumulation   current,
  0
);

// 5050

实际上,数学类操作符有一个 reduce 就足够了,因为上面说的 countmaxmin 的功能都可以通过 reduce 来实现。

# 条件布尔类操作符

# every

代码语言:javascript复制
import 'rxjs/add/operator/every';

const source$ = Observable.of(1, 2, 3, 4, 5);
const every$ = source$.every(x => x > 0);

// true

通常不要对一个永不完结的 Observable 对象使用 every 这个操作符,因为很可能产生的新 Observable 对象也是永不完结的。

# find 和 findIndex

有人说,RxJS 就是异步处理世界的 lodash。RxJS 和 lodash 的不同之处是,lodash 处理的都是一个内容确定的数据集合,比如一个数组或者一个对象,既然数据集合已经有了,所以对应的函数都是同步操作;对于 RxJS ,数据可能随着时间的推移才产生,所以更适合于异步数据处理。

代码语言:javascript复制
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/find';

const source$ = Observable.of(3, 1, 4, 1, 5, 9);
const find$ = source$.find(x => x % 2 === 0);

// 4

在某些情况下,如果既希望获得满足判定条件的数据,同时也获得这个数据的序号,也就是把 findfindIndex 的功能合在一起,该怎么做呢?

代码语言:javascript复制
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/find';
import 'rxjs/add/operator/findIndex';
import 'rxjs/add/operator/zip';

const source$ = Observable.of(3, 1, 4, 1, 5, 9);
const isEven = x => x % 2 === 0;
const find$ = source$.find(isEven);
const findIndex$ = source$.findIndex(isEven);
const zip$ = find$.zip(findIndex$);

// [4, 2]

# isEmpty

isEmpty 用于检查一个上游 Observable 对象是不是“空的”,所谓“空的” Observable 是指没有吐出任何数据就完结的 Observable 对象。

代码语言:javascript复制
import 'rxjs/add/observable/interval';
import 'rxjs/add/operator/isEmpty';

const source$ = Observable.interval(1000);
const isEmpty$ = source$.isEmpty();

// false

empty 产生的 Observable 对象作为 isEmpty 的上游,得到的会是 true

代码语言:javascript复制
import 'rxjs/add/observable/empty';
import 'rxjs/add/operator/isEmpty';

const source$ = Observable.empty();
const isEmpty$ = source$.isEmpty();

// true

只有上游 Observable 象吐出一个数据的时候, isEmpty 才能知道它“不空”,所以 isEmpty 产生的 Observable 对象吐出 true 的时机,要延迟到上游吐出数据的时刻。

# defaultIfEmpty

defaultIfEmpty 做的事情比 empty 更进一步,除了检测上游 Observable 对象是否为“空的”,还要接受一个默认值(default)作为参数,如果发现上游 Observable 对象是“空的”,就把这个默认值吐出来给下游;如果发现上游 Observable 不是“空的”,就把上游吐出的所有东西原样照搬转交给下游。

defaultIfEmpty 有一个缺点,是只能产生包含一个值的 Observable 对象,假如希望在上游为空的情况下产生一个包含多个数据的 Observable 对象,defaultIfEmpty 做不到。

0 人点赞