Rxjs - Subjects

102 阅读2分钟

每个Subject都是一个Observable。给定一个Subject,就可以订阅它,提供一个Observable,它将开始正常地接收值。从Observer的角度看,他不能说明Observable执行是来自一个普通的单播Observable还是一个Subject。

在Subject内部,subscribe不调用传递值的新执行。他只是在Observers列表中注册给定的Observer, 类似于addListener在其他库和语言中的工作方式。

每个Subject都是Observer。他是一个具有next(v),error(e)complete()方法的对象。要向Subject提供一个新值,只需调用next(theValue), 他就会多播给注册来监听Subject的Observers。

下面例子,我们有两个Observers连接到一个Subject,将一些值提供给Subject:

  const subject = new Subject<number>();
   
  subject.subscribe({
    next: (v) => console.log(`observerA: ${v}`),
  });
  subject.subscribe({
    next: (v) => console.log(`observerB: ${v}`),
  });
   
  subject.next(1);
  subject.next(2);
   
  // Logs:
  // observerA: 1
  // observerB: 1
  // observerA: 2
  // observerB: 2

因为Subject是一个Observer,这也意味着你可以提供一个Subject作为任何Observable的订阅的参数。如下:

  const subject = new Subject<number>();
   
  subject.subscribe({
    next: (v) => console.log(`observerA: ${v}`),
  });
  subject.subscribe({
    next: (v) => console.log(`observerB: ${v}`),
  });
   
  const observable = from([1, 2, 3]);
   
  observable.subscribe(subject); // You can subscribe providing a Subject
   
  // Logs:
  // observerA: 1
  // observerB: 1
  // observerA: 2
  // observerB: 2
  // observerA: 3
  // observerB: 3

如上,我们实际上只是通过Subject将单播Observable执行转换为多播。这演示了如何让任何Observable执行共享给多个Observers的唯一方法是Subject。

还有一些特殊的Subject类型:BehaviorSubjectReplaySubject, 和 AsyncSubject.

Multicasted Observables

“多播Observable”通过一个可能有许多订阅者的 Subject 传递通知,而普通的“单播Observable”只向单个Observer发送通知。

一个多播的Observable使用一个幕后的Subject让多个Observers看到相同的Observable执行。

在幕后,多播operator是这样工作的:Observers订阅底层的Subject,Subject订阅源Observable。以下示例与前面使用observable.subscribe(subject)的示例类似:

  const source = from([1, 2, 3]);
  const subject = new Subject();
  const multicasted = source.pipe(multicast(subject));
  
  // These are, under the hood, `subject.subscribe({...})`:
  multicasted.subscribe({
    next: (v) => console.log(`observerA: ${v}`),
  });
  multicasted.subscribe({
    next: (v) => console.log(`observerB: ${v}`),
  });
   
  // This is, under the hood, `source.subscribe(subject)`:
  multicasted.connect();

多播返回一个看起来像普通Observable的Observable,但是在订阅时像 Subject 一样工作。多播返回一个 ConnectableObserver,它只是一个connect()方法的Observable。

connect()方法对于确定共享Observable执行何时开始非常重要。因为connect()在底层执行 source.subscribe(subject) ,所以connect()返回一个Subscription,您可以unsubscribe,以取消共享的Observable执行。

Angular项目应用场景

比如在一个service中通过API获取某项data,而我有很多组件需要用这个data。可以这么写

  const subject = new Subject();
  // componentA
  subject.subscribe({
    next: (v) => console.log(`componentA: ${v}`),
  });
  // componentB
  subject.subscribe({
    next: (v) => console.log(`componentB: ${v}`),
  });
  // service
   setTimeout(()=>{
     subject.next('response data')
   }, 3000)
   
  // Logs:
  // componentA: response data
  // componentB: response data

参考: RxJS - Subject