理解 RxJS :四次元編程

學習 RxJS 最大的問題是官方造了不少概念,但文檔又解釋得不太全面和易懂,須要結合閱讀各類文章(特別是 Ben Lesh 的,包括視頻)。本文試圖總體梳理一遍再用另外的角度來介紹,但願能幫助初學者或者對 RxJS 的一些概念比較含糊的使用者。javascript

做者最近作了一個無縫結合 React 與 RxJS 的庫 observable-hooks,歡迎使用和星星🌟!

爲何須要 RxJS

RxJS 屬於響應式編程,其思想是將時間看做數組,隨着時間發生的事件被看做是數組的項,而後以操做數組的方式變換事件。其強大的地方在於站在四維的角度看問題,這就像是擁有了上帝視野。html

在處理事件之間的關係時,對於傳統方式,咱們須要設置各類狀態變量來記錄這些關係,好比對點擊 Shift 鍵進行計數,須要手動設置一個 let shiftPressCount: number,若是須要每 600ms 清零,又須要添加計時的狀態,這些狀態都須要手動維護,當它們變得複雜和龐大的時候咱們很快就會亂了,由於沒有明確的方向,很差判斷這些狀態同步了沒有。java

而這正是 RxJS 發光發熱的地方。由於從四維的角度看,這些狀態就不是單個變量,而是一系列變量。好比對按鍵計數:react

Rx.Observable.fromEvent(document, 'keydown')
  .filter(({ key }) => key === 'Shift')
  .scan(count => count + 1, 0)
  .subscribe(count => console.log(`按了 ${count} 遍 Shift 鍵`))

相信有使用過數組方法的人第一次看也大概能知道這裏幹了些什麼(把 scan 看做是會輸出中間結果的 reduce)。中間狀態都在變換的過程當中被封裝起來,每一次事件的 count 都是獨立的,不容易亂,也使得能夠用純函數去表達狀態的變換。鏈式調用(或者 RxJS5 的 pipeable)在必定程度上限制了狀態數據的流動方向,增長了可預測性,更加容易理解。git

理解 RxJS

基本概念

使用 RxJS 前先理解它要作什麼,這裏引入了兩個概念,Producer (生產者)和 Observer (觀察者)。es6

先看一個熟悉的例子:github

document.addEventListener('click', function handler (e) {
  console.log(e.clientX)
})

這裏的 Producer 是 DOM 事件機制,會不按期產出 MouseEvent 事件。Observer 就是 handler,對事件做出反應。編程

再看前面的例子:api

Rx.Observable.fromEvent(document, 'keydown')
  .filter(({ key }) => key === 'Shift')
  .scan(count => count + 1, 0)
  .subscribe(count => console.log(`按了 ${count} 遍 Shift 鍵`))

Producer 仍是 DOM 事件機制,Observer 是 subscribe 的參數。因此能夠理解 RxJS 爲鏈接 Producer 和 Observer 的紐帶。數組

因而這個紐帶的成分叫 Observable (可被觀察的)就不難理解了。Observable 就是由事件組成的四次元數組。RxJS 將 Producer 轉換爲 Observable,而後對 Observable 進行各類變換,最後再交給 Observer。

對 Observable 進行變換的操做符叫作 Operator,好比上面的 filterscan,它們輸入 Observable 再輸出新的 Observable。RxJS 有巨量的 Operators ,這也是學習 RxJS 的第二難點,我已經分類整理了六十多個,整理完會再寫一篇文章介紹,敬請關注。

建立 Observable

RxJS 封裝了許多有用的方法來將 Producer 轉換爲 Observable,好比 fromEventfromPromise,但其根本是一個叫 create 的方法。

var observable = Rx.Observable.create(observer => {
  observer.next(0)
  observer.next(1)
  observer.next(2)
  setTimeout(() => {
    observer.next(3)
    observer.complete()
  }, 1000)
})

這其實跟 Promise 的思路很像,Promise 只能 resolve 一遍,但這裏能夠 observer.next 不少個值(事件),最後還能 complete(不是必須的,能夠有無限事件)。官方把這個類 resolve 的參數也叫作 observer,由於 observer.next(0) 的意思是「Subscribe 個人那個 Observer 接下來會得到這個值 0」。我認爲這是一個很差的決定,重名對於新人太容易混淆了,這個其實能夠從另外一個角度看,把它叫作 producer,「產生」了下個值。

Subscribe 不是訂閱者模式

一個常見的誤解是認爲 RxJS 就是 addEventListener 那樣的訂閱者模式,subscribe 這個方法名也頗有誤導性。然而二者並非一回事,訂閱者模式會維護一個訂閱者列表,事件來了就一一調用列表上的每一個訂閱者傳遞通知。但 RxJS 並無這麼一個列表,它就是一個函數,能夠跟 Promise 類比,Promise 的 executor 是在 new Promise(executor) 時立刻執行的,而 RxJS Rx.Observable.create(observer)observer 則是在每次執行 subscribe 後都調用一遍,即每次 subscribe 的 Observables 都是獨立的,都會從新走一遍整個流程。

這個時候你也許會想,這樣每次都完整調用一遍豈不是很浪費性能?沒錯,若是須要屢次 subscribe 同個 Producer 這麼作會比較浪費,但若是隻是 subscribe 一遍,維護一個訂閱者列表也沒有必要。因此 RxJS 引入了 Hot 和 Cold Observable 的概念。

Hot & Cold

Observable 冷熱概念其實就是看 Producer 的建立受不受 RxJS 控制。

前面咱們知道,create 會將 Producer 轉化爲 Observable 。若是這個 Producer 也是在 create 回調裏面產生的,那麼就是 Cold ,由於 Producer 還不存在,只有 subscribe 了以後纔會被建立。

但若是 Producer 在以前就建立了,好比 DOM 事件,create 回調裏僅僅是對 Producer 添加 listener,那麼這就叫作 Hot ,由於不須要 subscribe 來啓動 Producer 。

只有 Hot Observable 才能夠實現訂閱者模式。能夠經過一個特殊的 Observable 叫 Subject 來建立,其內部會維護一個訂閱者列表。經過 share 方法能夠將一個 Cold 的 Observable 轉換爲 Hot 。原理是內部用 Subject subscribe 上流的 Observable 實現轉接。

使用 RxJS

理解了基本概念以後就能夠直接開寫了,自己沒有什麼魔法,參考一下 api 依樣畫葫蘆便可。

使用 RxJS 最多見的問題是不知道何時該用哪一個 Operator 。這其實跟數組操做是同樣的,RxJS 提供了數量龐大的 Operators ,基本覆蓋了各類能夠想到的數組操做,建議先從 JavaScript 常見的數組操做開始,如 mapfilterscan(也有 reduce ,但這個一般不是咱們想要的,咱們通常不須要在 complete 以後才輸出結果,而是每次都輸出階段性的結果)。

多翻官方文檔,經常使用的 Operators 都描述得很是詳細,有彈珠圖(Marble Graph)和一句話總結;缺點是措辭有時可能會比較抽象,不是那麼好理解。

更新:新的社區維護的 官方文檔已經作得很是不錯,推薦使用。

另外就是第三方的 learnrxjsRxjs 5 ultimate,按做者的思路組織,更通俗易懂些,能夠做爲補充理解;缺點是可能跟官方不一樣步,以及不全。

我整理完也會再寫一篇文章介紹,敬請期待。

相關文章
相關標籤/搜索