| 功能需求 | 适用的操作符 | | 统计数据流中产生的所有数据个数 | count
| | 获得数据流中最大或者最小的数据 | max
和 min
| | 对数据流中的数据进行规约操作 | reduce
| | 判断是否所有数据满足某个条件 | every
| | 找到第一个满足判定条件的数据 | find
和 findIndex
| | 判断一个数据流是否不包含任何数据 | 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
参数传递给规约函数的第一次调用。
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
就足够了,因为上面说的 count
、max
和 min
的功能都可以通过 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
在某些情况下,如果既希望获得满足判定条件的数据,同时也获得这个数据的序号,也就是把 find
和 findIndex
的功能合在一起,该怎么做呢?
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
对象。
import 'rxjs/add/observable/interval';
import 'rxjs/add/operator/isEmpty';
const source$ = Observable.interval(1000);
const isEmpty$ = source$.isEmpty();
// false
将 empty
产生的 Observable
对象作为 isEmpty
的上游,得到的会是 true
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
做不到。