原文:Debugging RxJS, Part 1: Tooling
譯者:Ice Panpan;校驗者:暫無
我是一個 Rxjs
的信仰者,我在我所有的專案中都使用 Rxjs
。有了 Rxjs
,我發現很多曾經覺得乏味的事都變得痛快。但是有一件事不是這樣:除錯。
Rxjs
中非同步的本質在組合之後讓除錯變得更具挑戰性:沒有太多的狀態(state)供你檢查,並且呼叫堆疊(call stack)也幫不了太大的忙。我過去使用的方法是在整個程式碼多處新增 do
操作符並且記錄,以此來檢查那些組合的 Observable
產生的值。這並不是我想要的方法,因為:
- 當我在除錯時修改程式碼,我不得不進行更多的日誌記錄工作;
- 當除錯結束之後,我必須刪除日誌記錄或者註釋掉它;
- 當在一個正常的組合Observable中存在‘拍扁’的操作時,如何進行日誌記錄需要格外的小心。
- 就算是專門有的
log
操作符,結果也不會很理想。
最近,我留了一些時間來為 Rxjs
構建一個除錯工具,我覺得這個工具必須具備以下的功能:
- 應該儘可能的不顯眼;
- 不需要通過修改程式碼來進行除錯;
- 在除錯結束後,不需要刪除或註釋掉除錯的程式碼;
- 應該可以輕鬆的啟用和禁用日誌記錄;
- 它應該提供與瀏覽器控制檯的一些整合————用於開啟/關閉除錯用能和檢查狀態等。
如果想要更完美,還要一些東西:
- 它應該支援暫停
Observable
; - 它應該支援修改
Observable
或者它們發出的值; - 它應該支援控制檯意外的日誌記錄機制;
- 它應該是可擴充套件的;
- 它應該在某種程度上可以捕獲視覺化訂閱依賴關係所需的資料。
考慮到這些功能,我建立了 rxjs-spy
。
核心概念
rxjs-spy
引入了 tag
操作符,將字串標記與 Observable
相關聯。這個操作符不會以任何方式更改 Observable
的行為或值。
tag
操作符可以被單獨匯入-js import "rxjs-spy/add/operator/tag"
-並且其他的 rxjs-spy
方法可以在生產環境下省略,所以唯一的開銷就是字串註釋。
大多數工具的方法接受匹配器,以確定它們將應用於哪些標記的 Observable
。匹配器可以是傳遞標籤本身的簡單字串,正規表示式或謂詞。
通過呼叫 spy
來配置工具時,它會修改 Observable.prototype.subscribe
來監聽所有的 subscriptions
, notifications
和 unsubscriptions
。這也就是意味著,只有已經被訂閱的 Observable
才會被監聽。
rxjs-spy
公開了一個旨在從程式碼中呼叫的模組API和一個用於在瀏覽器控制檯中互動使用的控制檯API。大多數時候,我早早地在應用程式啟動程式碼裡條用模組API的方法,並使用控制檯API進行剩餘的除錯。
控制檯API功能
在除錯時,我通常使用瀏覽器的控制檯來檢查和操作標記的 Observables
。控制檯API功能最容易通過示例解釋:
import { Observable } from "rxjs/Observable";
import { spy } from "rxjs-spy";
import "rxjs/add/observable/interval";
import "rxjs/add/operator/map";
import "rxjs/add/operator/mapTo";
import "rxjs-spy/add/operator/tag";
spy();
const interval = new Observable
.interval(2000)
.tag("interval");
const people = interval
.map((value) => {
const names = ["alice", "bob"];
return names[value % names.length];
})
.tag("people")
.subscribe();
複製程式碼
rxjs-spy
中的控制檯API通過 rxSpy
在全域性暴露。
呼叫 rxSpy.show()
將顯示所有已經被標記的 Observable
的列表,指示其狀態(incomplete
,complete
或者 errored
),訂閱者(subscribers
)的數量和最近發出的值(如果已經發出一個值)。控制檯輸出將如下所示:
要顯示特定標記的 Observable
的資訊,可以將標記名稱或者正規表示式傳遞給 show
:
可以通過呼叫 rxSpy.log
來顯示被標記的 Observable
的日誌資訊:
log
不帶引數呼叫將會顯示所有標記的 Observable
的日誌記錄。
模組API中的大多數方法都返回一個撤銷功能,可以呼叫該功能來撤銷方法呼叫。在控制檯中,管理起來很繁瑣,所以還有另一種選擇。
呼叫 rxSpy.undo()
將顯示已經呼叫的方法的列表:
呼叫 rxSpy.undo
並傳遞與方法呼叫關聯的數字將看到該呼叫的撤銷函式被執行。例如,呼叫 rxSpy.undo(3)
將看到被標記為 interval
的 Observable
的記錄被撤銷之後的結果:
有時,在除錯時修改 Observable
或其值時,這個方法就很有用。控制檯API包含一種 let
方法,其功能與 RxJS
中的 let
操作符大致相同。它的實現方式是通過呼叫 let
方法對標記的 Observable
的當前和未來的訂閱者產生影響。例如。以下呼叫將看到 people
Observable
發射 mallory
而不是 alice
或 bob
:
與 log
方法一樣,let
可以撤消對該方法的呼叫:
能夠在除錯時暫停一個 Observable
對我來說幾乎是不可或缺的。呼叫 rxSpy.pause
將暫停一個標記的 Observable
,並返回一個可用於控制和檢查 Observable
的通知(notifications
)的 deck
:
在該 deck
上呼叫 log
將顯示 Observable
是否暫停,並顯示被暫停的通知(notifications
)。(通知是 Notification
使用 materialize
操作符獲得的rxjs例項)
在 deck
上呼叫 step
將發出一個被暫停住的通知(notifications
):
呼叫 resume
將發出所有被暫停的通知(notifications
),並將恢復 Observable
:
呼叫 pause
將看到 Observable
重新進入暫停狀態:
很容易忘記將返回的 deck
分配給變數,因此控制檯API包含一個 deck
方法,和 undo
方法行為相似。呼叫它將顯示 pause
呼叫的列表:
呼叫它並傳遞與呼叫相關聯的數字將返回相對應的 deck
:
像 log
和 let
的呼叫一樣,pause
的呼叫也可以撤銷。撤銷 pause
的呼叫將看到標記的 Observable
恢復正常:
希望以上的例子可以對 rxjs-spy
的控制檯API進行一個概述。Debugging RxJS
的後續部分將重點介紹 rxjs-spy
的具體功能以及如何使用它們來解決實際的除錯問題。
對我來說,rxjs-spy
肯定讓除錯Rxjs不再那麼繁瑣。
更多資訊
rxjs-spy
的程式碼可以在 GitHub上找到,並且有一個線上的控制檯API示例。
該包可以通過NPM進行安裝。
有關本系列的一下篇文章,請參閱除錯 Rxjs(二):日誌記錄