「这是我参与2022首次更文挑战的第25天,活动详情查看:2022首次更文挑战」
buffer、window
buffer 和 window 都是用来进行对数据进行缓存的操作符,它接收一个通知 Observable 作为参数,原始 Observable 每次产生数据会进入一个缓存中,每次通知 Observable 触发时,当前缓存的内容会作为一个整体输出。二者的区别在于 buffer 缓存是一个数组,window 缓存是一个 Observable。
buffer 的弹珠图:
window 的弹珠图:
bufferCount、windowCount
除了最基础的 buffer 和 window 外,还有一系列相关联的缓存操作符,bufferCount 和 windowCount 是一组基于数量的缓存操作符,可以接受数量作为参数,指定每几个数据缓存为一组。
bufferCount 的弹珠图:
windowCount 的弹珠图:
bufferTime、windowTime
从名字可以看出来,bufferTime 和 windowTime 是根据时间来进行缓存的,接收一个时间参数,每隔一个时间段内的数据被划分进一个缓存组。
bufferTime 的弹珠图:
windowTime 的弹珠图:
bufferToggle、windowToggle
这一组是比较灵活的缓存策略,他接收一个起始 Observable 和一个终止函数,以起始 Observable 产生数据作为缓存开始标识,以终止函数返回触发时作为终止标识,在每一次起始和终止之间做一个缓存,实现一个可控性比较强的缓存效果。
bufferToggle 的弹珠图:
windowToggle 的弹珠图:
bufferWhen、windowWhen
与 bufferToggle 和 windowToggle 相比,bufferWhen 和 windowWhen 没有起始 Observable,它的一切行为都由终止函数决定,前一次缓存终止后会接着产生新一次缓存。bufferWhen 和 windowWhen 也适用于需要高度定制化的缓存场景。
bufferWhen 弹珠图:
windowWhen 弹珠图:
scan
scan 实现了一个累积的效果,与我们常见的 reduce 操作类似(在 Rxjs 中也有 reduce 效果不同),他会把每次累积的结果输出来,使用 scan 可以轻松实现类似 redux 的效果。这里我们看一个使用 scan 计算斐波那契数列的过程:
const firstTwoFibs = [0, 1];
const fibonnaci$ = interval(1000).pipe(
scan(([a, b]) => [b, a + b], firstTwoFibs),
map(([, n]) => n),
startWith(...firstTwoFibs)
);
fibonnaci$.subscribe(console.log);
scan 的弹珠图:
mergeScan、switchScan
mergeScan 与 scan 其实很类似,不过它每次返回的是一个 Observable,switchScan 是 Rxjs 7 开始引入的 switch 策略的 scan,这部分内容我没使用过,网上资料也不多,可以参考相关资料,这里不展开了。
expand
expand 实现的是递归调用的效果,每次处理时可以接收上一次调用结果作为参数,举个例子:
of(2).pipe(expand(val => of(1 + val))).subscribe(v => console.log(v));
expand 的弹珠图:
partition
根据条件把一路流拆为两路流,可以处理条件分支场景(partition 操作符已过时,这里需要使用静态方法调用),举个例子:
const observableValues = of(1, 2, 3, 4, 5, 6);
const [evens$, odds$] = partition(observableValues, (value, index) => value % 2 === 0);
odds$.subscribe(x => console.log('odds', x));
evens$.subscribe(x => console.log('evens', x));
// odds 1
// odds 3
// odds 5
// evens 2
// evens 4
// evens 6
弹珠图:
pairwise
将当前值与前一次的值一起发出来,举一个很实用的例子,计算鼠标两次点击的距离:
fromEvent(document, 'click').pipe(
pairwise(),
map(pair => {
const x0 = pair[0].clientX;
const y0 = pair[0].clientY;
const x1 = pair[1].clientX;
const y1 = pair[1].clientY;
return Math.sqrt(Math.pow(x0 - x1, 2) + Math.pow(y0 - y1, 2));
}),
).subscribe(x => console.log(x))
弹珠图描述:
groupBy
根据某些条件对数据进行分组,返回一个高阶 Observable:
const people = [
{ name: 'Sue', age: 25 },
{ name: 'Joe', age: 30 },
{ name: 'Frank', age: 25 },
{ name: 'Sarah', age: 35 }
];
from(people).pipe(groupBy(p => p.age));
弹珠图:
至此常见的转换操作符就介绍完了,有了转换操作符,我们可以使用 Rxjs 来实现一些复杂的功能,下一步将开始过滤操作符的学习,这几部分都是非常基础的用法,需要熟练掌握。