「这是我参与2022首次更文挑战的第27天,活动详情查看:2022首次更文挑战」
debounce、debounceTime
在程序开发中 debounce 和 throttle 大家都不陌生,在 Rxjs 中通常使用这类操作符进行积压处理和舍弃,在 Rxjs 中除了 debounce 和 throttle,还有 audit 和 sample,这四个操作符对应的是四种不同的处理策略。这四个原始的操作符都是接收一个返回 Observable 的函数作为参数,通过这个 Observable 发出数据开进行控制。此外每一个操作符还提供了一个简化版的 xxxTime 操作符,xxxTime 操作符接收时间作为参数,可以更方便的实现根据时间来进行控制的效果,为了方便描述这里我们以 xxxTime 为例进行介绍。
首先来看 debounceTime,debounce 是防抖,它的效果是在一定时间内如果没产生新数据就直接发出,debounce 我们其实不陌生,在处理无效的连续点击时一定都用过,使用 Rxjs 实现:
fromEvent(document, 'click').pipe(debounceTime(1000)).subscribe(x => console.log(x));
这里 1000 毫秒内连续点击就不会打印,当停止点击 1000 毫秒后打印。
这里我们只看 xxxTime 系列的弹珠图,debounceTime 的弹珠图如下:
throttle、throttleTime
throttle 是截流,它的作用效果是忽略一定时间内的值,throttle 在开发中也很常用,我们可以用来限制点击频率,使用 Rxjs 实现:
fromEvent(document, 'click')clicks.pipe(throttleTime(1000)).subscribe(x => console.log(x));
这里如果连续点击每 1000 毫秒内只会打印一次,注意与 debounce 的区别。
throttleTime 的弹珠图:
audit、auditTime
audit 的策略与 throttle 类似,也是一定时间段只取一个,区别在于 throttle 取得是第一个,而 audit 取最后一个,上面点击的例子也可以使用 auditTime:
fromEvent(document, 'click')clicks.pipe(auditTime(1000)).subscribe(x => console.log(x));
这里可以看到区别,使用 auditTime 是在 1000 毫秒开始第一次打印。
auditTime 弹珠图:
sample、sampleTime
sample 一个重要的特点是固定时间间隔,它的效果是每隔固定的时间查看一次是否产生过新数据,如果有取最新数据发出,使用 sampleTime 控制点击:
fromEvent(document, 'click')clicks.pipe(sampleTime(1000)).subscribe(x => console.log(x));
这里无论怎样的点击频率,每一秒最多只打印一次,这里看起来效果不明显,它最本质的特点是不依赖数据关系。
弹珠图:
有关四个操作符的详细区别可以看这个例子,这里面的弹珠图描述的非常直观。
distinct
distinct 可以对数据进行去重,使用 distinct 之后数据流中只会发出新值忽略重复值,它默认是比较值,可以传入一个函数来设置比较特定的 key,举个例子:
of(1, 1, 2, 2, 2, 1, 2, 3, 4, 3, 2, 1).pipe(distinct()).subscribe(x => console.log(x));
// 1
// 2
// 3
// 4
of({ age: 4, name: 'Foo'}, { age: 7, name: 'Bar'}, { age: 5, name: 'Foo'}).pipe(distinct(p => p.name)).subscribe(x => console.log(x));
// { age: 4, name: 'Foo' }
// { age: 7, name: 'Bar' }
distinctUntilChanged、distinctUntilKeyChanged
与 distinct 不同,distinctUntilChanged 指的是未发生变化时去重,它是和上一次进行比较,上面的例子换成 distinctUntilChanged 后结果就大不相同了:
of(1, 1, 2, 2, 2, 1, 2, 3, 4, 3, 2, 1).pipe(distinctUntilChanged()).subscribe(x => console.log(x));
// 1
// 2
// 1
// 2
// 3
// 4
// 3
// 2
// 1
distinctUntilChanged 可以接收一个比较函数作为参数来控制比较策略,如果想像类似 distinct 一样传入一个函数设置比较 key 可以使用 distinctUntilKeyChanged 来替代。
single
找到一个符合条件的内容,如果找不到或找到多个会抛错误:
of(1, 2, 3).pipe(single(x => x === 2)).subscribe(x => console.log(x));
// 2
到这里常见的过滤操作符就介绍完了,至此组合转换过滤几个基本的操作已经都介绍过了, 使用这几种操作符可以完成大部分常见的需求。此外 Rxjs 中还有几种其他类型的操作符,这些在特定的场景中很有用,下一部分来介绍这些操作符。