[譯] 認識 rxjs 中的 Subject
原文連結: Understanding rxjs Subjects
原文作者:Luuk Gruijs;發表於2018年4月17日
RxJS 是真的好用,它可以幫助我們更好地編輯/訂閱資料流。雖然單用 Observable(可觀察物件)就可以做很多事情,但 RxJS 還是提供了多種用於操控資料流的類,Subject(主題)就是其中之一。
如果你還不知道 Observable 是什麼的話,建議先讀讀我的另一篇文章: Understanding, creating and subscribing to observables in Angular 。如果你覺得你明白 Observable 是什麼意思,那行咱繼續!

攝影:Anvesh Uppunuthula,來自Unsplash
Subject
Subject 就好比 Observable。你可以訂閱它,就像你平時訂閱 Observable 一樣。它也有類似 next()
, error()
以及 complete()
的方法,就像你平時傳給 Observable 建構函式的 observer(觀察者)一樣。
使用 Subject 主要是為了多播(multicast)。Observable 預設是單播(unicast)的,而單播就意味著:對於每個訂閱者,都只有一個獨立的 Observable execution 與之對應。證明如下:
import * as Rx from "rxjs"; const observable = Rx.Observable.create((observer) => { observer.next(Math.random()); }); // 訂閱者甲 observable.subscribe((data) => { console.log(data); // 0.24957144215097515 (隨機數) }); // 訂閱者乙 observable.subscribe((data) => { console.log(data); // 0.004617340049055896 (隨機數) }); 複製程式碼
由於 Observable 在設計上就是單播的,所以如果你希望使多個訂閱者收到相同的資料,那麼用 Observable 可能會非常麻煩。而 Subject 可以幫助我們解決這個問題。正如先前所說,Subject 可以用來實現多播。多播的基本含義是:一個 Observable execution 可以在多個訂閱者之間共享。
譯者注:每當我們呼叫一次 Observable.subscribe()
時,一個新的 Observable execution 就會被啟動。詳見Observable。
Subject 也可比作事件發射器(EventEmitter),其中註冊了多個事件監聽器。當我們訂閱 Subject 時,它並不會啟動一個新的 execution 來傳送資料。而是在現有觀察者列表中註冊一個新的觀察者,僅此而已。
如何在多播中使用 Subject
多播是 Subject 的特性,使用 Subject 即可實現多播,無需任何技巧。下面是一個簡單的示例:
import * as Rx from "rxjs"; const subject = new Rx.Subject(); // 訂閱者 1 subject.subscribe((data) => { console.log(data); // 0.24957144215097515 (隨機數) }); // 訂閱者 2 subject.subscribe((data) => { console.log(data); // 0.24957144215097515 (隨機數) }); subject.next(Math.random()); 複製程式碼
奶思!我們使兩個訂閱者獲得了相同的資料。然而,這並非 Subject 的唯一用途。
相比 Observable 只能作為資料的生產者,Subject 即可以作為生產者,也可以作為消費者。通過把 Subject 作為消費者使用,你可以將一個單播 Observable 轉換為多播。示例如下:
import * as Rx from "rxjs"; const observable = Rx.Observable.create((observer) => { observer.next(Math.random()); }); const subject = new Rx.Subject(); // 訂閱者 1 subject.subscribe((data) => { console.log(data); // 0.24957144215097515 (隨機數) }); // 訂閱者 2 subject.subscribe((data) => { console.log(data); // 0.24957144215097515 (隨機數) }); observable.subscribe(subject); 複製程式碼
將我們的 subject 傳遞給 subscribe()
,使其接收由 observable 傳來的值(消費資料)。隨後,subject 的所有訂閱者都會立即收到這個值。