Subject介紹:Subject, ReplaySubject, BehaviorSubject, AsyncSubject

Subject 是什麼?

官方原文解釋

**What is a Subject?** An RxJS Subject is a special type of Observable that allows values to be multicasted to many Observers. While plain Observables are unicast (each subscribed Observer owns an independent execution of the Observable), Subjects are multicast.

一行文解釋:是 Observable 也是 Observer,且可以廣播(multicast)給多位訂閱者!

宣告出 Subject 後,可以在多處訂閱(.subscribe())

當 Subject 發出事件(.next())
所有訂閱(.subscribe())的地方,都會收到事件,並開始他自己的管道(.pipe())流水線
即是廣播(multicast)

所以第一篇文章才會說:為Angular而學RxJs者,Subject 必學!
也是 Subject 的廣播,讓 Angular 可以輕鬆跨越層層Component更新畫面

Subject – 最基本的樣子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const subject = new Subject<number>();

subject.subscribe({
next: (v) => console.log(`observerA: ${v}`)
}); // 第一個訂閱
subject.subscribe({
next: (v) => console.log(`observerB: ${v}`)
}); // 第二個訂閱

subject.next(1); // 發送事件1
subject.next(2); // 發送事件2

// 輸出結果:
// observerA: 1
// observerB: 1
// observerA: 2
// observerB: 2

BehaviorSubject – 須帶初始值

需要一初始值,且會記錄目前的的值
當有新的訂閱出現時,則直接發送目前值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
const subject = new BehaviorSubject<number>(0);


subject.subscribe({
next: (v) => console.log(`observerA: ${v}`)
}); // 第一個訂閱

subject.next(-1); // 訂閱observerB之前,先發送-1

subject.subscribe({
next: (v) => console.log(`observerB: ${v}`)
}); // 第二個訂閱

subject.next(1); // 發送事件1
subject.next(2); // 發送事件2

// 輸出結果:
// observerA: 0 <-- 僅A訂閱,發送初始值
// observerA: -1 <-- 發送-1,A接收到
// observerB: -1 <-- B加入訂閱,取得最後一次的發送結果-1
//
// observerA: 1 <-- 以下為 next 後,發出的值
// observerB: 1
// observerA: 2
// observerB: 2

ReplaySubject – 回放曾經發送的事件

顧名思義,Replay就是會重送所有結果
當新的訂閱加入時,會把所有曾經發送過的結果再次發送

可以入參決定回放幾次
或不傳,全部回放

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
const REPLAY_COUNTS = 3; // 指定重放次數
const subject = new BehaviorSubject<number>(REPLAY_COUNTS); // 可以入參決定回放幾個,或不傳也行,就是全部回放


subject.subscribe({
next: (v) => console.log(`observerA: ${v}`)
}); // 第一個訂閱

subject.next(-1); // 訂閱observerB之前,先發送3次
subject.next(-2);
subject.next(-3);
subject.next(-4);

subject.subscribe({
next: (v) => console.log(`observerB: ${v}`)
}); // 第二個訂閱

subject.next(1); // 發送事件1
subject.next(2); // 發送事件2

// 輸出結果:
// observerA: -1 <-- 發送 -1~ -4,僅A接收到
// observerA: -2
// observerA: -3
// observerA: -4
//
// observerB: -2 <-- B加入訂閱,回放最後3次結果
// observerB: -3
// observerB: -4
//
// observerA: 1 <-- 以下為 next 後,發出的值
// observerB: 1
// observerA: 2
// observerB: 2

new ReplaySubject(1)時,就相當於new BehaviorSubject(初始值)了!
而他們之間有2點不同

  1. BehaviorSubject的初始值,是寫在constructor的
  2. ReplaySubject是回放內容,若出錯拋error,照樣回放!而BehaviorSubject不會照丟error

AsyncSubject – complete了才處理最後一次內容

只有當complete時才會發送內容
且只會發送最後一筆資料
新加入的訂閱,也會收到complete的最後內容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const subject = new AsyncSubject<number>();


subject.subscribe({
next: (v) => console.log(`observerA: ${v}`)
}); // 第一個訂閱

subject.next(-1); // 訂閱observerB之前,先發送
subject.next(-2);
subject.complete(); // 完結!

subject.subscribe({
next: (v) => console.log(`observerB: ${v}`)
}); // 第二個訂閱

// 由於前面已經`complete`,後面的所有發送也不會有任何反應
subject.next(1); // 發送事件1
subject.next(2); // 發送事件2

// 輸出結果:
// observerA: -2 <-- complete後,A才接收到最後結果 -2
// observerB: -2 <-- 在complete後,B才加入訂閱,取得complete後的最後結果 -2
// <-- 因已complete,next亦不會接收任何結果

系列文章

RxJs教學系列文章