[译] 认识 rxjs 中的 BehaviorSubject、ReplaySubject 以及 AsyncSubject

1,054 阅读3分钟
juejin.cn/post/684490… ----转载

多播的基本含义是:一个 Observable execution 可以在多个订阅者之间共享。

Subject 的作用是实现 Observable 的多播。由于其 Observable execution 是在多个订阅者之间共享的,所以它可以确保每个订阅者接收到的数据绝对相等。不仅使用 Subject 可以实现多播,RxJS 还提供了一些 Subject 的变体以应对不同场景,那就是:BehaviorSubject、ReplaySubject 以及 AsyncSubject。

1,BehaviorSubject 的特性就是它会存储“当前”的值。这意味着你始终可以直接拿到 BehaviorSubject 最后一次发出的值。

2,ReplaySubject 是可以给新订阅者发送“旧”数据的。另外,ReplaySubject 还有一个额外的特性就是它可以记录一部分的 observable execution,从而存储一些旧的数据用来“重播”给新来的订阅者。

当创建 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 并指定其只存储最近两次广播的值;
  • 订阅 subject 并称其为订阅者A;
  • subject 连续广播三次,同时订阅者A 也会跟着连续打印三次;
  • 这一步就轮到 ReplaySubject 展现魔力了。我们再次订阅 subject 并称其为订阅者B,因为之前我们指定 subject 存储最近两次广播的值,所以 subject 会将上两个值“重播”给订阅者B。我们可以看到订阅者B 随即打印了这两个值;
  • subject 最后一次广播,两个订阅者收到值并打印。


  • 之前提到了你还可以设置 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 


  • 我们创建了一个 ReplaySubject,指定其存储最近两次广播的值,但只保留 100ms;
  • 订阅 subject 并称其为订阅者A;
  • 我们让这个 subject 每 200ms 广播一次。订阅者A 每次都会收到值并打印;
  • 我们设置在程序执行一秒后再次订阅 subject,并称其为订阅者B。这意味着在它开始订阅之前,subject 就已经广播过五次了。由于我们在创建 subject 时就设置了数据的过期时间为 100ms,而广播间隔为 200ms,所以订阅者B 在开始订阅后只会收到前五次广播中最后一次的值。

  • 3,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