RxJS v6 学习指南 (9)

返回上游数据流的镜像 Observable,当上游的 Observable 完结或出错时调用传给它的函数,不影响数据流。

interval(1000).pipe( take(6), map(x => { if (x === 4) { throw new Error('unlucky number 4') } else { return x } }), finalize(() => console.log('finally')) ).subscribe(x => console.log('a')) tap 操作符

我们可以使用 tap 操作符来进行调试。

拦截源 Observable 的每一次发送,执行一个函数,返回源 Observable 的镜像 Observable。

这个 API 有助于我们对 Observable 的值进行验证(debug)和执行一个会带来副作用的函数,而不会影响源 Observable。如我们用鼠标进行 canvas 绘图,鼠标按下是开始画图,鼠标松开即停止。我们需要在 mousedown 的时候进行 moveTo,否则这次画的会和上次画的连在一起。我们应该把这个会带来副作用过程放在 tap 操作符的函数中,这样才不会影响原来的数据流。

tap 操作符和订阅并不相同,tap 返回的 Observable 如果没有被订阅,tap 中产生副作用的函数并不会执行。

其他一些操作符

1) repeat

repeat 用来重复上游 Observable

2)pluck 类似 lodash 的方法 pluck,提取对象的嵌套属性的值。

const click$ = fromEvent(document, 'click') const tagName$ = click$.pipe(pluck('target', 'tagName')) tagName$.subscribe(x => console.log(x))

等价于:

click$.pipe(map(e => e.target.tagName))

3)toArray

将发出的数据汇聚为数组

interval(1000).pipe( take(3), toArray() ).subscribe(x => console.log(x)) // [0, 1, 2]

4)partition

将上游的 Observable 分为两个,一个 Observable 的数据是符合判定的数据,另一个时不符合判定的数据。

const part$ = interval(1000).pipe( take(6), partition(x => x % 2 === 0) ) part$[0].subscribe(x => console.log(x)) // 0, 2, 4 part$[1].subscribe(x => console.log(x)) // 1, 3, 5

5) 更多操作符

RxJS 中的操作符非常多,这里只介绍了一部分,更多请查看官网 API。

RxJS 最经典的例子——AutoComplete

有一个用于搜索的 input,当输入时自动发送 ajax,并在下方显示结果列表,然后可以选择结果,这就是我们常见的 AutoComplete 效果。要实现这个效果有很多细节要考虑,如防止 race condition 和优化请求次数。

<div> <input type="search" autocomplete="off"> <ul></ul> </div>

先获取两个 DOM 元素:

const input = document.querySelector('#search'); const suggestList = document.querySelector('#suggest-list');

我们先将输入框的 input 的事件转化为 Observable。

const input$ = fromEvent(input, 'input');

然后我们根据输入的值去发送 ajax 请求,由于我们是要获取最新的值而丢弃之前 ajax 返回的值,我们应该使用 switchMap 操作符。通过使用这个操作符,我们解决了 race condition 问题。

input$.pipe( switchMap(e => from(getSuggestList(e.target.value))) )

getSuggestList 是一个发送 ajax 请求的方法,返回 promise,我们使用 from 来将其转化为 Observable。

为了优化请求,首先 e.target.value 是空字符串时不应该发送请求,然后可以使用 debounceTime 减少触发频率,也可以使用 distinctUntilChanged 操作符来表示只有与上次不同时才去发送请求。我们还可以在 API 失败时重试 3 次。

input$.pipe( filter(e => e.target.value.length > 1), debounceTime(300), distinctUntilChanged(), switchMap( e => from(getSuggestList(e.target.value)).pipe(retry(3)) ) )

然后我们去订阅渲染就可以了。

对于结果列表上的点击事件,比较简单,具体见demo。

操作符和数组方法

Observable 的操作符和数组的方法有相似之处,但是也有很大的不同,体现在以下两点:

延迟运算

渐进式取值

延迟运算,我们之前有讲到过,就是只有订阅后才会开始对元素进行运算。

因为 Observable 是时间上的集合,操作符不是像数组方法那样运算完所有元素再返回交给下一个方法,而是一个元素一直运算到底,就像管道中的水流一样,先发出的数据先经过操作符的运算。

多播

前面的例子都是只有一个订阅者的情况,实际上当然可以有多个订阅者,这就是多播(multicast),即一个数据流的内容被多个 Observable 订阅。

Hot Observable 和 Cold Observable

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpdzpj.html