RxJS笔记(四)Subject主体

文章目录

    • 多播 Observables (Multicasted Observables)
        • 引用计数 refCount()
    • 1. 行为主体 BehaviorSubject
    • 2. 重播主体 ReplaySubject
    • 3. 异步主体 AsyncSubject
    • 4. void 主体 Void subject

普通的 Observable 是单播的(每个订阅的 Observer 都拥有 Observable 的独立执行)

Subject是一种特殊类型的 Observable,允许将值多播到多个 Observer

Subjects 就像 EventEmitters:它们维护着许多监听器的注册表。

  1. 每个 Subject 都是 Observable。
    给定一个 Subject,你可以 subscribe 它,提供一个 Observer,它将开始正常接收值。
    从 Observer 的角度来看,它无法判断 Observable 的执行是来自普通的单播 Observable 还是来自 Subject。
  2. 每个 Subject 也都是 Observer。
    是一个具有方法 next(v)、error(e) 和 complete() 的对象。
    要为 Subject 提供一个新值,只需调用 next(theValue),它将被多播到注册进来监听 Subject 的 Observer。
    (由于 Subject 是 Observer,这也意味着你可以提供 Subject 作为任意 Observable subscribe 的参数
import { Subject, from } from 'rxjs';
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 类型还有一些特化: BehaviorSubject、ReplaySubject 和 AsyncSubject。

多播 Observables (Multicasted Observables)

多播的 Observable 在底层使用 Subject 来让多个 Observer 看到相同的 Observable 执行过程。

  • e.g. multicast
import { from, Subject, multicast } from 'rxjs';

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();

multicast 返回一个 ConnectableObservable,它只是一个带有 connect() 方法的 Observable。
connect() 在后台执行 source.subscribe(subject),所以 connect() 返回一个订阅,你可以退订以取消共享的 Observable 执行过程。

引用计数 refCount()

手动调用 connect() 并处理订阅通常很麻烦。通常,我们希望在第一个 Observer 抵达时自动连接,并在最后一个 Observer 退订时自动取消共享执行。

e.g. 执行

  1. 第一个 Observer 订阅了多播的 Observable
  2. 多播的 Observable 已连接
  3. next 值 0 被传递给第一个 Observer
  4. 第二个 Observer 订阅了多播的 Observable
  5. next 的值 1 被传递给第一个 Observer
  6. next 的值 1 被传递给第二个 Observer
  7. 第一个 Observer 退订多播的 Observable
  8. next 值 2 被传递给第二个 Observer
  9. 第二个 Observer 退订多播的 Observable
  10. 与多播的 Observable 的连接被退订

refCount 能使多播的 Observable 在第一个订阅者抵达时自动开始执行,并在最后一个订阅者离开时停止执行。

const refCounted = source.pipe(multicast(subject), refCount());

refCount() 方法只存在于 ConnectableObservable 上,它返回一个 Observable,而不是另一个 ConnectableObservable。

1. 行为主体 BehaviorSubject

Subjects 的变体之一是 BehaviorSubject,它具有“当前值”的概念。
它存储发送给其消费者的最新值,并且每当有新的 Observer 订阅时,它将立即从 BehaviorSubject 接收到“当前值”

import { BehaviorSubject } from 'rxjs';
const subject = new BehaviorSubject(0); // 0 is the initial value

subject.subscribe({
  next: (v) => console.log(`observerA: ${v}`),
});
subject.next(1);
subject.next(2);
subject.subscribe({
  next: (v) => console.log(`observerB: ${v}`),
});
subject.next(3);

// Logs
// observerA: 0
// observerA: 1
// observerA: 2
// observerB: 2  //第二个 Observer 接收到值 2,即使它是在发送值 2 之后订阅的。
// observerA: 3
// observerB: 3

2. 重播主体 ReplaySubject

ReplaySubject 与 BehaviorSubject 类似,它可以将旧值发送给新订阅者,但它也可以记录 Observable 执行结果的一部分。

ReplaySubject 会记录来自 Observable 执行的多个值,并将它们重播给新订阅者。

可以指定要重播的值的数量

import { ReplaySubject } from 'rxjs';
const subject = new ReplaySubject(3); // buffer 3 values for new subscribers

subject.subscribe({
  next: (v) => console.log(`observerA: ${v}`),
});

subject.next(1);
subject.next(2);
subject.next(3);
subject.next(4);

subject.subscribe({
  next: (v) => console.log(`observerB: ${v}`),
});

subject.next(5);

// Logs:
// observerA: 1
// observerA: 2
// observerA: 3
// observerA: 4
// observerB: 2
// observerB: 3
// observerB: 4
// observerA: 5
// observerB: 5

除了缓冲区大小之外,你还可以指定一个以毫秒为单位的窗口时间,以确定记录的值可以存在多长时间。

//使用 100 个元素的大型缓冲区,但窗口时间参数仅为 500 毫秒
const subject = new ReplaySubject(100, 500 /* windowTime */);

3. 异步主体 AsyncSubject

仅将 Observable 执行的最后一个值发送给其 Observer,并且仅在执行完成时发送

AsyncSubject 类似于 last() 操作符,因为它会等待 complete 通知以传递单个值。

import { AsyncSubject } from 'rxjs';
const subject = new AsyncSubject();

subject.subscribe({
  next: (v) => console.log(`observerA: ${v}`),
});

subject.next(1);
subject.next(2);
subject.next(3);
subject.next(4);

subject.subscribe({
  next: (v) => console.log(`observerB: ${v}`),
});

subject.next(5);
subject.complete();

// Logs:
// observerA: 5
// observerB: 5

4. void 主体 Void subject

有时,发出值这件事本身比所发出的值更重要。
通过声明一个 void 主体,你可以表明该值是无所谓的。只有事件本身才重要。

import { Subject } from 'rxjs';

// const subject = new Subject();
const subject = new Subject(); // Shorthand for Subject

subject.subscribe({
  next: () => console.log('One second has passed'),
});

setTimeout(() => subject.next(), 1000);

在版本 7 之前,Subject 值的默认类型是 any。
Subject 禁用发出值的类型检查,而 Subject 可以防止意外访问所发出的值。

你可能感兴趣的:(RxJs,rxjs,js)