我們在開發復雜的 Angular 應用時,經常會使用到 Rxjs 的 defer 函數,例如:

創建一個 Observable,在訂閱時調用 Observable 工廠為每個新的 Observer 創建一個 Observable 對象。

該函數接收一個輸入參數,類型為一個工廠函數。輸出為一個 Observable 對象,一旦被訂閱時,其綁定的工廠函數會被調用。

defer 的實質是延遲創建機制,即只有在返回的 Observable被訂閱時,才開始創建 Observable 對象。

defer 允許你只在 Observer 訂閱時創建一個 Observable。 它一直等到 Observer 訂閱它,調用給定的工廠函數來獲取一個 Observable —— 工廠函數通常會生成一個新的 Observable —— 并將 Observer 訂閱到這個 Observable。 如果工廠函數返回一個假值,則使用 EMPTY 作為 Observable 代替。 最后但并非最不重要的是,工廠函數調用期間的異常通過調用 error 傳遞給觀察者。

看下面這個具體的例子。

我們來單步調試下上面這段代碼。首先進入 defer 內部執行邏輯:

在 defer 內部,直接構造一個新的 Observable,并且將工廠函數傳入。該工廠函數在第8行被調用,用于生成一個包含應用程序業務邏輯的 Observable 對象,存儲在 input 里。最后,將應用程序的subscriber 訂閱到這個工廠函數返回的 Observable 上。

我們再單步執行,發現程序執行流從上圖的第5行,跳轉到了 第16行。這體現了 defer 函數延遲創建 Observable 對象的行為。所謂延遲創建,準確的說,應該是延遲了包含業務邏輯的 Observable 對象的創建。

緊接著,回到我們的應用代碼,此時針對 defer 函數返回的 wrapper Observable 對象調用 subscribe,這時候就會觸發包含業務邏輯的 Observable 對象的創建了:

defer 返回的 wrapper Observable 的訂閱函數在此處執行:

調用工廠方法,進行包含業務邏輯的 Observable 對象創建:

當前隨機數執行結果大于 0.5,返回 fromEvent 生成的新 Observable 對象。

緊接著,第24行的匿名函數 x => console.log(x),每當屏幕被鼠標點擊時,就會觸發。這個匿名函數本來是訂閱到 defer 函數返回的 wrapper Observable 對象的。當工廠函數返回了新的 Observable 對象后,它被自動訂閱到這個新的 Observable 對象上。

總結 defer 的工作原理:

(1) defer 函數被調用時,傳入一個工廠函數作為輸入參數。這個工廠函數返回一個新的包含了業務邏輯的 Observable 對象。

(2) defer 函數返回另一個新的 Observable 對象,這個 Observable 對象稱為 wrapper 或者 dummy Observable 對象,因為它不包含任何業務邏輯,存活的唯一價值就是,實現業務邏輯 Observable 對象的延遲創建。

(3) 當 wrapper Observable 被訂閱時,觸發工廠函數的執行,生成新的 Observable 對象,同時通知其 Observer.

更多Jerry的原創文章,盡在:"汪子熙":