[譯] 調試 RxJS 第2部分: 日誌篇

原文連接: blog.angularindepth.com/debugging-r…
本文爲 RxJS 中文社區 翻譯文章,如需轉載,請註明出處,謝謝合做!
若是你也想和咱們一塊兒,翻譯更多優質的 RxJS 文章以奉獻給你們,請點擊【這裏】javascript

日誌沒什麼可興奮的。html

然而,日誌是獲取足夠信息以開始推斷問題的直接方式,它不是靠猜的,並且它一般用於調試 RxJS 代碼。java

本文是調試 RxJS 系列文章的第二篇,繼 調試 RxJS 第1部分: 工具篇以後,側重於使用日誌來解決實際問題。在本文中,我將展現如何以一種不唐突的方式來使用 rxjs-spy 獲取詳情和有針對性的信息。react

來看一個簡單示例,示例中使用的是 rxjsrxjs-spy 的 UMD bundles:git

RxSpy.spy();
RxSpy.log(/user-.+/);
RxSpy.log('users');

const names = ['benlesh', 'kwonoj', 'staltz'];
const users = Rx.Observable.forkJoin(...names.map(name =>
  Rx.Observable
    .ajax
    .getJSON(`https://api.github.com/users/${name}`)
    .tag(`user-${name}`)
))
.tag('users');

users.subscribe();複製代碼

示例中使用 forkJoin 來組成一個發出 GitHub 用戶數組的 observable 。es6

rxjs-spy 對使用 tag 操做符標記過的 observables 起做用,tag 操做符使用字符串標籤名來註釋 observable,僅此而已。在組成 observable 以前,示例啓用了偵察,併爲匹配 /user-.+/ 正則表達式或標籤名爲 users 的 observable 配置日誌記錄器。github

示例的輸入看上去應該是這樣的:ajax

除了 observable 的 nextcomplete 通知,日誌輸出還包括了訂閱和取消訂閱的通知。它顯示了所發生的一切:正則表達式

  • 訂閱組合 observable 會並行訂閱每一個用戶 API 請求的 observable
  • 請求完成的順序是不固定的
  • observables 所有完成
  • 所有完成後,組合 observable 的訂閱會自動取消訂閱

每一個日誌中的通知都包含接收該通知的訂閱者 ( Subscriber )的信息,其中包括訂閱者訂閱的數量和 subscribe 調用的堆棧跟蹤:typescript

堆棧跟蹤指向的是根源的 subscribe 調用,也就是 observable 訂閱者的顯式訂閱。因此,用戶請求 observables 的堆棧跟蹤也指向 medium.js (譯者注: 即上面的代碼文件) 中的 subscribe 調用:

當調試時,我發現知道實際的 subscribe 調用地點比知道位於組合 observable 中間的 subscribe 調用地點更有用。

如今咱們來看一個現實問題。

當編寫 redux-observable 的 epics 或 ngrxeffects 時,我見過一些開發者的代碼大概是這樣的:

import { Observable } from 'rxjs/Observable';
import { ajax } from 'rxjs/observable/dom/ajax';

const getRepos = action$ =>
  action$.ofType('REPOS_REQUEST')
    .map(action => action.payload.user)
    .switchMap(user => ajax.getJSON(`https://api.notgithub.com/users/${user}/repos`))
    .map(repos => { type: 'REPOS_RESPONSE', payload: { repos } })
    .catch(error => Observable.of({ type: 'REPOS_ERROR' }))
    .tag('getRepos');複製代碼

乍看上去沒什麼問題,並且大多數狀況下也能正常運行。這種 bug 仍是在單元測試裏發現不了的。

問題就是有時候 epic 就會中止運行。再具體一點就是當 dispatch 了報錯的 action 後它會中止運行。

日誌顯示了具體發生了什麼:

發出報錯的 action 後, observable 便完成了,由於 redux-observable 的基礎設施取消了 epic 的訂閱。catch 操做符的文檔解釋了這一現象發生的緣由:

不管 selector 函數返回的 observable 是什麼,都會被用來繼續執行 observable 鏈。

在 epic 中,catch 返回的 observable 完成了,epic 也就完成了。

解決方法是將 mapcatch 的調用移到 switchMap 裏面,就像這樣:

import { Observable } from 'rxjs/Observable';
import { ajax } from 'rxjs/observable/dom/ajax';

const getRepos = action$ =>
  action$.ofType('REPOS_REQUEST')
    .map(action => action.payload.user)
    .switchMap(user => ajax
      .getJSON(`https://api.notgithub.com/users/${user}/repos`)
      .map(repos => { type: 'REPOS_RESPONSE', payload: { repos } })
      .catch(error => Observable.of({ type: 'REPOS_ERROR' }))
    )
    .tag('getRepos');複製代碼

這樣 epic 便不會完成,它會繼續 dispatch 報錯的 actions:

在這兩個示例中,對於被調試的代碼來講,惟一須要修改就是是添加了某個標記註釋。

註釋是輕量級的,只需添加一次,我傾向於將它們留在代碼中。tag 操做符的使用能夠獨立於 rxjs-spy 中診斷功能,經過使用 rxjs-spy/add/operator/tag 或直接從 rxjs-spy/operator/tag 導入。因此保留標籤的成本很小。

日誌記錄器可使用正則表達式來配置,這會致使了多種可能性的標記。例如,使用像 github/usersgithub/repos 這樣的複合標籤就可讓全部標記名以 github 開頭的 observables 啓用日誌。

日誌沒什麼可興奮的,可是從日誌的輸出中收集到的信息一般能夠節省大量的時間。採用靈活的標記方法能夠進一步減小處理日誌相關代碼的時間。

相關文章
相關標籤/搜索