「这是我参与2022首次更文挑战的第28天,活动详情查看:2022首次更文挑战」
在学习操作符之前首先要理解 Rxjs 中单播和多播的概念,在 Rxjs 中 Observable 分为 Cold Observable 和 Hot Observable 两种,默认的 Observable 都是 Cold Observable,它的特点是每一次新的订阅都是一个全新的数据源,举个例子:
const source$ = interval(1000).take(3);
source$.subscribe((value) => console.log('A ' + value))
setTimeout(() => {
source$.subscribe((value) => console.log('B ' + value))
}, 1000)
// A 0
// A 1
// B 0
// A 2
// B 1
// B 2
这里添加了 A 和 B 两个订阅,虽然 B 比 A 晚 1 秒,但是 B 还是会收到 0、1、2 三个完整的打印,也就是说实际上 B 和 A 是两个不同的数据源,每一个数据源里面都会有完整的从头开始的数据,如果此时添加一个 C 订阅,C 也会再创建一个新的数据源,每次订阅都是单个的数据源,这种行为叫做单播,这样的 Observable 称为 Cold Observable。
在实际开发中经常会有共享数据,前端开发中一个最基本的需求就是全局状态,我们想要的是不论在哪里不论什么时候获取拿到的都是最新数据,这样的这样我们就需要将 Cold Observable 变成 Hot Observable。对于 Hot Observable,每次订阅的都是同一个数据源,这样相当于是一份数据传给多个订阅者,这样的行为叫做多播。
怎样实现多播呢?一个很常见的思路是使用一个中介者订阅原始数据,再把数据转发给 A 和 B:
const source$ = interval(1000).take(3);
const subject = {
observers: [],
subscribe(target) {
this.observers.push(target);
},
next: function(value) {
this.observers.forEach((next) => next(value))
}
}
source.subscribe(subject);
subject.subscribe((value) => console.log('A ' + value))
setTimeout(() => {
subject.subscribe((value) => console.log('B ' + value))
}, 1000)
// A 0
// A 1
// B 1
// A 2
// B 2
这里的 subject 就充当了这个中介者的角色,它可以订阅也可以转发,在 Rxjs 中已经给我们提供了具有这样能力的对象 Subject,因此这里我们把 subject 换成 new Subject(),上面的例子效果是一样的。
关于 Subject 对象的详细介绍我们再 Subject 一节再展开,这里主要看一下多播相关的操作符,在最新版本中 Rxjs 废弃了一系列多播相关的操作符,改用 connect 方法来实现,目前还保留的操作符有 shaer 和 shareReplay。
share
share 的作用是把原生的流变为多播流,内部也是通过多播 Subject 来实现的,举个例子:
const source = interval(1000).pipe(take(3), share());
source.subscribe((x) => console.log('A: ', x)),
setTimeout(
() => source.subscribe((x) => console.log('B: ', x)),
2000
);
// A 0
// A 1
// A 2
// B 2
弹珠图:
shareReplay
shareReplay 与 share 的区别在于它支持在订阅时重播最近的几个值,其内部是使用 ReplaySubject 来实现的,这里的区别就在与 replay 的能力。
多播的重点还是在于对 Subject 的理解,因此这部分介绍操作符比较简单,关于 Subject 本身还有很多强大的应用,这部分也都放在 Subject 一节介绍。