[譯] 除錯 RxJS 第1部分: 工具篇

SangKa發表於2017-11-09

原文連結: 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,而不是 alicebob

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 物件:

就像 loglet 呼叫一樣,pause 呼叫也可以取消,並且取消 pause 呼叫會恢復標記的 observable:

希望上面的示例會讓你對 rxjs-spy 以及它的控制檯 API 有一個大致的瞭解。「 除錯 RxJS 」系統的後續部分會專注於 rxjs-spy 的具體功能,以及如何使用它來解決實際的除錯問題。

對於我而言,rxjs-spy 確實可以使除錯 RxJS 變得有趣起來。

更多資訊

rxjs-spy 的原始碼託管在 GitHub 上,這裡有一個可以操作控制檯 API 的線上示例

還可以通過 NPM 來安裝包。

本系列的下篇文章 —「 除錯 RxJS 第2部分:日誌篇

相關文章