[翻譯] 調試 Rxjs(二):日誌記錄

原文:Debugging RxJS, Part 2: Logginghtml

譯者:Ice Panpan;校驗者:暫無react

日誌記錄並非一件讓人興奮的事。git

然而,這是得到足夠的信息來推理問題最直接的方法,而不須要去猜想。它一般是調試 RxJS 代碼的首選方法。這是這個系列文章的第二篇,專一於使用日誌記錄來解決實際問題。在第一篇調試 Rxjs(一):工具中,主要介紹的是 rxjs-spy。在本文中,我將展現如何使用 rxjs-spy 以最小的影響來獲取詳細並有針對性的信息。es6

讓咱們看一個使用 rxjsrxjs-spy UMD捆綁的簡單案例:github

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用戶數組的 Observableajax

rxjs-spy 使用 tag 操做符來標記 Observable,而且僅僅經過字符串來給 Observable 註釋。這個示例在組合 Observable 以前,首先啓用監聽功能,並配置了哪些 Observable 要被記錄——匹配 /user-.+/ 的正則表達式或者帶有 users 標籤的那些 Observable正則表達式

這個示例的控制檯輸出以下:redux

除了 Observablenextcomplete 的通知以外,記錄的輸出還包括訂閱和取消訂閱的通知。它顯示了發生的一切:api

  1. 對組合的 Observable 的訂閱影響的每個用戶API請求的 Observable 的並行訂閱;
  2. 請求以任意順序完成;
  3. Observable 所有完成;
  4. 而且在所有完成後取消對組合 Observable 的訂閱。

每一個記錄的通知還包括有關接受通知的訂閱者的信息——包括訂閱者具備的訂閱量以及 subscribe 調用的堆棧痕跡:數組

堆棧痕跡指的是 subscribe 調用的根——即影響訂閱者對 Observable 訂閱的顯式調用。所以,用戶請求的 Observable 的堆棧痕跡也參考了 medium.js 中的 subscribe 調用:

當我調試時,我發現知道調用 subscribe 的實際的根位置比知道組合 Observable 中某個 subscribe 的位置更有用。

如今讓咱們看一個現實中實際的問題。

在編寫 redux-observable epicsngrx effects 時,我看到幾個開發人員相似的代碼:

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。

問題是,它有時會中止工做,特別是在一個錯誤的動做發生以後。

記錄顯示正在發生的事:

在錯誤的動做被髮射出去以後,看到 redux-observalbe基礎結構從epic中解除訂閱的 Observable 完成了。該文檔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將再也不完成,並繼續發送錯誤動做:

在這兩個示例中,須要對正在調試的代碼進行的惟一修改是添加了一些標記註釋。

註釋的影響很小,一旦添加,我傾向於將它們留在代碼中。標籤運算符能夠獨立於診斷 rxjs-spy 使用——使用rxjs-spy/add/operator/tag 或直接導入 rxjs-spy/operator/tag,所以保留標記的開銷很小。

能夠使用正則表達式配置記錄器,這能夠產生許多可能的標記方法。例如,使用複合標記,例如 github/usersgithub/repos 將容許您爲全部被標記後存儲在存儲庫裏的 github Observable 啓用日誌記錄。

記錄並不使人興奮,但能夠從記錄的輸出中收集的信息一般能夠節省大量時間。採用靈活的標記方法能夠進一步減小處理與日誌記錄相關的代碼所花費的時間。

相關文章
相關標籤/搜索