原文連結: blog.angularindepth.com/debugging-r…
本文為 RxJS 中文社群 翻譯文章,如需轉載,請註明出處,謝謝合作!
如果你也想和我們一起,翻譯更多優質的 RxJS 文章以奉獻給大家,請點選【這裡】
我是一位 RxJS 信徒,在我所有活躍的專案中都在使用它。用了它之後,我發現很多乏味的事現在都變得很簡單。然而,有一件事卻沒有任何好轉,那就是除錯。
由於 RxJS 的可組合性與有時是非同步的本質使得除錯變成了一種挑戰:沒有太多的狀態可以觀察,而且呼叫堆疊基本也沒什麼幫助。我之前的做法是在整個程式碼庫中穿插大量的 do
操作符和日誌來檢查流經組合 observables 的值。由於以下幾點原因,我對這種方法並不滿意:
- 我總是在不斷地新增日誌,除錯的同時還要更改程式碼
- 除錯完成後,對於日誌,我要麼一條條的進行手動刪除,要麼選擇忍受
- 匆忙之中將
do
操作符隨意放置在一個組合 observable 中間時,應該避免有條件的日誌輸出的太恐怖 - 即使是專門的日誌操作符,其體驗也不理想
最近,我花費了一些時間開發了一個 RxJS 的除錯工具。它有如下幾個功能,而且我覺得是這個工具必須要具備的:
- 它應該儘可能地不唐突
- 它應該不需要靠不斷修改程式碼來進行除錯
- 特別是,它應該不需要解決問題後靠手動刪除或註釋掉除錯程式碼
- 它應該支援可以輕鬆啟用和禁用的日誌
- 它應該支援捕獲可以隨時間進行比較的快照
- 它應該提供一些與瀏覽器控制檯的整合,用於開啟/關閉除錯功能和檢查狀態,等等
還有一些功能,如果能有就更好了:
- 它應該支援暫停 observables
- 它應該支援修改 observables 或 observables 發出的值
- 它應該支援除控制檯之外的日誌機制
- 它應該是可擴充套件的
- 它應該採取一些方法來捕獲視覺化訂閱依賴所需的資料
綜合考慮這些功能後,我開發了 rxjs-spy
。
核心概念
rxjs-spy
引入了 tag
操作符,它將一個字串標籤和一個 observable 關聯起來。這個操作符並沒有以任何方式來改變 observable 的行為和值。
tag
操作符可以單獨使用: import "rxjs-spy/add/operator/tag"
。這樣的話,rxjs-spy
的其他方法會在生成版本中被忽略,所以唯一的開銷就是字串的使用 (匯入)。
大多數工具方法都接受匹配器 ( matchers ),以確定它們即將應用哪些標記過的 observables 。匹配器可以是簡單的字串、正規表示式或傳遞標籤本身的函式謂詞 ( predicates )。
當通過呼叫工具的 spy
方法配置後,它會在 Observable.prototype.subscribe
上打補丁,這樣它就能夠偵察到所有的訂閱、通知和取消訂閱。當然,只有被訂閱的 observables 才能通過 spy
進行偵察。
rxjs-spy
公開了一個模組 API 用於在程式碼中呼叫,還公開了一個控制檯 API 供使用者在瀏覽器的控制檯中進行互動。大多數時候,我都是在應用的啟動程式碼中早早地呼叫模組 API 的 spy
方法,然後使用控制檯 API 來執行剩下的除錯工作。
控制檯 API 功能
除錯時,我通常使用瀏覽器的控制檯來檢查和操縱標記過的 observables 。控制檯 API 還是通過示例來解釋比較容易,下面的程式碼示例展示瞭如何與 observables 配合使用:
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()
會顯示所有標記過的 observables 列表,並表明它們的狀態 (未完成、已完成或報錯)、訂閱者的數量以及最新發出的值 (如果有值發出的話)。控制檯輸出是像這樣的:
要顯示某個特定的標記 observable,需要將標籤名或正規表示式傳給 show
:
通過呼叫 rxSpy.log
可以啟用某個標記 observable 的日誌:
呼叫 log
時不帶任何引數會啟用所有標記 observables 的日誌。
模組 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 通知的 deck 物件:
呼叫 deck 的 log
方法會顯示 observable 是否暫停和暫停期間的所有通知 (通知是使用 materialize
操作符獲取的 RxJS 的 Notification
例項)。
呼叫 deck 的 setp
方法會發出一條通知:
呼叫 resume
方法會發出所有暫停期間的通知並恢復 observable:
呼叫 pause
會看到 observable 再次回到暫停狀態:
很容易會忘記將返回的 deck 賦值給了哪個變數,所以控制檯 API 還提供了 deck
方法,它的行為類似於 undo
方法。呼叫它會顯示所有 pause
呼叫的列表:
使用 pause
呼叫相關聯的數字來呼叫 deck
方法並會返回相關聯的 deck 物件:
就像 log
和 let
呼叫一樣,pause
呼叫也可以取消,並且取消 pause
呼叫會恢復標記的 observable:
希望上面的示例會讓你對 rxjs-spy
以及它的控制檯 API 有一個大致的瞭解。「 除錯 RxJS 」系統的後續部分會專注於 rxjs-spy
的具體功能,以及如何使用它來解決實際的除錯問題。
對於我而言,rxjs-spy
確實可以使除錯 RxJS 變得有趣起來。
更多資訊
rxjs-spy
的原始碼託管在 GitHub 上,這裡有一個可以操作控制檯 API 的線上示例。
還可以通過 NPM 來安裝包。
本系列的下篇文章 —「 除錯 RxJS 第2部分:日誌篇 」