我們在開發(fā)復(fù)雜的 Angular 應(yīng)用時,經(jīng)常會使用到 Rxjs 的 defer 函數(shù),例如:

創(chuàng)建一個 Observable,在訂閱時調(diào)用 Observable 工廠為每個新的 Observer 創(chuàng)建一個 Observable 對象。

該函數(shù)接收一個輸入?yún)?shù),類型為一個工廠函數(shù)。輸出為一個 Observable 對象,一旦被訂閱時,其綁定的工廠函數(shù)會被調(diào)用。

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

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

看下面這個具體的例子。

我們來單步調(diào)試下上面這段代碼。首先進入 defer 內(nèi)部執(zhí)行邏輯:

在 defer 內(nèi)部,直接構(gòu)造一個新的 Observable,并且將工廠函數(shù)傳入。該工廠函數(shù)在第8行被調(diào)用,用于生成一個包含應(yīng)用程序業(yè)務(wù)邏輯的 Observable 對象,存儲在 input 里。最后,將應(yīng)用程序的subscriber 訂閱到這個工廠函數(shù)返回的 Observable 上。

我們再單步執(zhí)行,發(fā)現(xiàn)程序執(zhí)行流從上圖的第5行,跳轉(zhuǎn)到了 第16行。這體現(xiàn)了 defer 函數(shù)延遲創(chuàng)建 Observable 對象的行為。所謂延遲創(chuàng)建,準確的說,應(yīng)該是延遲了包含業(yè)務(wù)邏輯的 Observable 對象的創(chuàng)建。

緊接著,回到我們的應(yīng)用代碼,此時針對 defer 函數(shù)返回的 wrapper Observable 對象調(diào)用 subscribe,這時候就會觸發(fā)包含業(yè)務(wù)邏輯的 Observable 對象的創(chuàng)建了:

defer 返回的 wrapper Observable 的訂閱函數(shù)在此處執(zhí)行:

調(diào)用工廠方法,進行包含業(yè)務(wù)邏輯的 Observable 對象創(chuàng)建:

當(dāng)前隨機數(shù)執(zhí)行結(jié)果大于 0.5,返回 fromEvent 生成的新 Observable 對象。

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

總結(jié) defer 的工作原理:

(1) defer 函數(shù)被調(diào)用時,傳入一個工廠函數(shù)作為輸入?yún)?shù)。這個工廠函數(shù)返回一個新的包含了業(yè)務(wù)邏輯的 Observable 對象。

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

(3) 當(dāng) wrapper Observable 被訂閱時,觸發(fā)工廠函數(shù)的執(zhí)行,生成新的 Observable 對象,同時通知其 Observer.

更多Jerry的原創(chuàng)文章,盡在:"汪子熙":