演示地址
https://rxviz.com/examples/custom
什么是有损回压控制?
举个例子:两根漏斗型管道汇集到一根管道中,要求两根管道按1:1的比例流出,但一根进水比较量,就会在这根管道上积水
在rxjs中,zip操作符就有这样的问题,因为受下游处理速度的控制,上游数据传入下游的速度跟不上上游数据传入的速度,就会在上游缓冲区积压数据
解决办法:可以通过舍弃掉一些传入的数据的方式来控制缓冲区积压数据的大小
除了有损回压控制,还有一种无损回压控制,就是通过缓存窗口(buffer类)实现的,本文不讲
有哪些有损回压控制操作符
进行有损回压控制用的是过滤操作符,有throttle、debounce、audit、sample
还有对应上⾯四个操作符的带Time后缀的简化版操作符:
throttleTime、debounceTime、auditTime、sampleTime
之所以称之为简化版,是因为带Time后缀的操作符,入参是毫秒数,是通过固定时间来控制流量
不带Time后缀的操作符,可入参是函数,这个函数返回一个Observable对象,Observable对象产生数据,通过动态产生的数据控制流量
本文主要讲上面几个操作符的区别
除此之外,还有distinct、distinctUntilChanged、distinctUntilKeyChanged、ignoreElement、elementAt、single,这几个操作符比较好区分
用时间控制流量
带Time的有损回压过滤操作符,包括 throttleTime、debounceTime、auditTime、sampleTime
debounceTime
debounceTime 是我们经常用来做防抖的操作符,其入参称为dueTime,表示等待时间
即在一个数据产生后的dueTime内没有新的数据生成,就将数据传给下游
const { fromEvent } = Rx;
const { map, filter, debounceTime } = RxOperators;
const input = document.createElement('input');
input.setAttribute('placeholder', 'Type something');
input.style.marginBottom = '100px'
output.prepend(input);
input.focus();
fromEvent(input, 'keydown').pipe(
debounceTime(500),
map(e => e.key),
filter(key => key !== ' ')
)
throttleTime
throttleTime用于截流,其入参成为duration,表示截流的时间区间
即在一个数据产生后,这个数据会传给下游,但是duration内产生的其他数据,被废弃掉
const { fromEvent } = Rx;
const { map, filter, debounceTime, throttleTime } = RxOperators;
const input = document.createElement('input');
input.setAttribute('placeholder', 'Type something');
input.style.marginBottom = '100px'
output.prepend(input);
input.focus();
fromEvent(input, 'keydown').pipe(
throttleTime(2000),
map(e => e.key),
filter(key => key !== ' ')
)
auditTime
auditTime 和 throttleTime 做相似的工作,不同的是在duration内,throttle把第⼀个数据传给下游,audit是把最后⼀个数据传给下游
const { fromEvent } = Rx;
const { map, filter, auditTime } = RxOperators;
const input = document.createElement('input');
input.setAttribute('placeholder', 'Type something');
input.style.marginBottom = '100px'
output.prepend(input);
input.focus();
fromEvent(input, 'keydown').pipe(
auditTime(2000),
map(e => e.key),
filter(key => key !== ' ')
)
sampleTime
sampleTime 跟前面三个操作符不同的地方在于,它不依赖数据的前后关系
sampleTime 有一个自己的固定时间区间,每个区间内取最后一个数据,在区间结束时将数据传给下游,所以sampleTime 传给下游的数据是时间区间的整数倍,这使得数据序列分布变得很均匀
const { interval } = Rx;
const { take, mapTo, concat, sampleTime } = RxOperators;
interval(500).pipe(
take(2),
mapTo('A'),
concat(interval(1000).pipe(
take(3),
mapTo('B'))
),
concat(interval(500).pipe(
take(3),
mapTo('C'))
),
sampleTime(800)
)
用数据控制流量
不带Time的有损回压过滤操作符,包括 throttle、debounce、audit、sample
入参为 durationSelector,如果durationSelector只是返回固定延时产⽣数据的Observable对象,那么和带Time的没有区别
如
const { timer, interval } = Rx;
const { throttle } = RxOperators;
const durationSelector = value => {
return timer(2000);
};
interval(1000).pipe(
throttle(durationSelector)
)
等同于
const { timer, interval } = Rx;
const { throttle } = RxOperators;
interval(1000).pipe(
throttleTime(2000)
)
不过,durationSelector有参数,就是当前传给下游的数据,所以完全可以根据这个参数来产⽣更灵活的操作
例如,可以把上⾯代码中的durationSelector改为如下的实现:
const durationSelector = value => {
return Observable.timer(value % 3 === 0 ? 2000 : 1000);
};
相当于throttleTime的duration时间可以控制,变成不是固定时间
对于debounce、audit、sample也是一样的道理