BehaviorSubjectReplaySubject 都是繼承於 Subject,兩者皆可以紀錄訂閱內容並在新的訂閱者出現時提供舊有的訂閱內容,簡單說就是替 Subject 增加回播功能。表面上兩者差異只有前者能夠儲存一個內容,而後者能夠儲存多個內容,但實際上可不只有這些,本文將帶你深入探討其中奧妙。(rxjs 版本為 6.5.5)

在此整理了一份兩者對回播功能的處理方式。

BehaviorSubject

  • 擁有初始值,且當外部傳入新的訂閱內容時,會一併修改初始值。
  • 回播初始值。

ReplaySubject

  • 擁有紀錄訂閱內容的陣列,並可以設定其紀錄數量,當外部傳入新的訂閱內容時,會放入此陣列。
  • 回播陣列。
  • 能夠只取至目前為止一段時間內的訂閱內容。
  • 即便已經完成(complete),在本身取消訂閱(unsubscribe)前都能夠回播。

看完兩者回播方式的差異後,再藉由原始碼了解內部的行為。

BehaviorSubject

建構式為 constructor(_value: T)
一定要填入一個初始值(_value),當外部傳入新的訂閱內容時,會去修改 _value;當有新的訂閱者出現時,能夠直接提供初始值給訂閱者。

ReplaySubject

建構式為 constructor(bufferSize: number = Number.POSITIVE_INFINITY, windowTime: number = Number.POSITIVE_INFINITY, scheduler?: SchedulerLike)

  • bufferSize 為紀錄數量,預設為無限大,當數值小於 1 時,以 1 取代。
  • windowTime 為只取多長時間內(milliseconds)的訂閱內容,預設為無限大,也就是不限制時間,當數值小於 1 時,以 1 取代。
  • scheduler 因為本文著重於回播功能,所以此變數先不談。

當外部傳入新的訂閱內容時,會將訂閱內容記錄在陣列保存,若超出紀錄數量,則將最舊的移出陣列。

當有新的訂閱者出現時,若 windowTime 為無限大則直接根據陣列內容依序提供給訂閱者;否則會將超過特定時間的紀錄排除。且回播時,並不會因為 Subject 已經完成(complete)導致isStopped 為真,而選擇不回播,只是改變訂閱時回傳的 subscription 物件為 Subscription.EMPTY

參考資料
RxJS 官網
BehaviorSubject Source Code
ReplaySubject Source Code
Subject Source Code