原文连接:Understanding rxjs BehaviorSubject, ReplaySubject and AsyncSubject
原文做者:Luuk Gruijs;发表于2018年5月4日
译者:yk;如需转载,请注明出处,谢谢合做!javascript
Subject 的做用是实现 Observable 的多播。因为其 Observable execution 是在多个订阅者之间共享的,因此它能够确保每一个订阅者接收到的数据绝对相等。不只使用 Subject 能够实现多播,RxJS 还提供了一些 Subject 的变体以应对不一样场景,那就是:BehaviorSubject、ReplaySubject 以及 AsyncSubject。java
若是你还不知道 Subject(主题)是什么的话,建议先读读个人上一篇文章:认识 rxjs 中的 Subject。若是你以为 OK 没问题,那咱继续!git
摄影:Cory Schadt,来自 Unsplashgithub
BehaviorSubject 是 Subject 的变体之一。BehaviorSubject 的特性就是它会存储“当前”的值。这意味着你始终能够直接拿到 BehaviorSubject 最后一次发出的值。api
有两种方法能够拿到 BehaviorSubject “当前”的值:访问其 .value
属性或者直接订阅。若是你选择了订阅,那么 BehaviorSubject 将直接给订阅者发送当前存储的值,不管这个值有多么“久远”。请看下面的例子:app
import * as Rx from "rxjs";
const subject = new Rx.BehaviorSubject(Math.random());
// 订阅者 A
subject.subscribe((data) => {
console.log('Subscriber A:', data);
});
subject.next(Math.random());
// 订阅者 B
subject.subscribe((data) => {
console.log('Subscriber B:', data);
});
subject.next(Math.random());
console.log(subject.value)
// 输出
// Subscriber A: 0.24957144215097515
// Subscriber A: 0.8751123892486292
// Subscriber B: 0.8751123892486292
// Subscriber A: 0.1901322109907977
// Subscriber B: 0.1901322109907977
// 0.1901322109907977
复制代码
详细讲解一下:dom
.value
属性的形式获取了 subject 当前的值并打印。这在同步的场景下很是好用,由于你没必要订阅 Subject 就能够获取它的值。另外,你可能发现了 BehaviorSubject 在建立时是须要设置一个初始值的。这一点在 Observable 上就很是难实现,而在 BehaviorSubject 上,只要传递一个值就好了。async
译者注:当前版本的 RxJS 中
BehaviorSubject()
是必需要设置初始值的,不然会致使执行错误,而原文并无体现这一点。因此我在这一段作了较多改动,以避免误导读者。详见 BehaviorSubject。post
相比 BehaviorSubject 而言,ReplaySubject 是能够给新订阅者发送“旧”数据的。另外,ReplaySubject 还有一个额外的特性就是它能够记录一部分的 observable execution,从而存储一些旧的数据用来“重播”给新来的订阅者。ui
当建立 ReplaySubject 时,你能够指定存储的数据量以及数据的过时时间。也就是说,你能够实现:给新来的订阅者“重播”订阅前一秒内的最后五个已广播的值。示例代码以下:
import * as Rx from "rxjs";
const subject = new Rx.ReplaySubject(2);
// 订阅者 A
subject.subscribe((data) => {
console.log('Subscriber A:', data);
});
subject.next(Math.random())
subject.next(Math.random())
subject.next(Math.random())
// 订阅者 B
subject.subscribe((data) => {
console.log('Subscriber B:', data);
});
subject.next(Math.random());
// Subscriber A: 0.3541746356538569
// Subscriber A: 0.12137498878080955
// Subscriber A: 0.531935186034298
// Subscriber B: 0.12137498878080955
// Subscriber B: 0.531935186034298
// Subscriber A: 0.6664809293975393
// Subscriber B: 0.6664809293975393
复制代码
简单解读一下代码:
以前提到了你还能够设置 ReplaySubject 的数据过时时间。让咱们来看看下面这个例子:
import * as Rx from "rxjs";
const subject = new Rx.ReplaySubject(2, 100);
// 订阅者A
subject.subscribe((data) => {
console.log('Subscriber A:', data);
});
setInterval(() => subject.next(Math.random()), 200);
// 订阅者B
setTimeout(() => {
subject.subscribe((data) => {
console.log('Subscriber B:', data);
});
}, 1000)
// Subscriber A: 0.44524184251927656
// Subscriber A: 0.5802631630066313
// Subscriber A: 0.9792165506699135
// Subscriber A: 0.3239616040117268
// Subscriber A: 0.6845077617520203
// Subscriber B: 0.6845077617520203
// Subscriber A: 0.41269171141525707
// Subscriber B: 0.41269171141525707
// Subscriber A: 0.8211466186035139
// Subscriber B: 0.8211466186035139
复制代码
一样解读一下代码:
BehaviorSubject 和 ReplaySubject 均可以用来存储一些数据,而 AsyncSubject 就不同了。AsyncSubject 只会在 Observable execution 完成后,将其最终值发给订阅者。请看代码:
import * as Rx from "rxjs";
const subject = new Rx.AsyncSubject();
// 订阅者A
subject.subscribe((data) => {
console.log('Subscriber A:', data);
});
subject.next(Math.random())
subject.next(Math.random())
subject.next(Math.random())
// 订阅者B
subject.subscribe((data) => {
console.log('Subscriber B:', data);
});
subject.next(Math.random());
subject.complete();
// Subscriber A: 0.4447275989704571
// Subscriber B: 0.4447275989704571
复制代码
虽然这段代码的输出并很少,但咱们仍是照例解读一下:
BehaviorSubject、ReplaySubject 和 AsyncSubject 均可以像 Subject 同样被用于多播。它们各自都有一些额外的特性以适用于不一样场景。
译者注:这个结论好敷衍。。。