關於 redux side effects

在開發前端 SPA 的時候,我們有一大半的時間再處理異步動作,更具體來說的話就是網路請求(ajax)。

在一般的使用情境下的流程大概會是這樣的 network request flow

處理從請求開始到請求結束的流程在 redux only 下,我們可以透過 store.subscribe 去監聽 actions,然後進一步的調用異步方法,並在異步方法結束的時候 dispatch 相對應的 action。

但如果註冊為 middleware 而不是 subscribe store 的話,不但可以取得 store/action 甚至進而調整輸出的 action。

到這邊,其實光是用來舉例的單單一個 action 在不管是 subscribe store 或是 middleware 裡面的實作,從冗長的 switch 判斷就知道這樣的解決方式是一個不好的方案。

redux-thunk

redux-thunk 是 redux 異步處理 middleware 的開拓者,他非常簡單易懂 (不過其實在接觸thunk初期的時候我根本不知道 dispatch 從哪來,有興趣的人可以看一下 redux-thunk source code,極短)

但在更為複雜的架構下就顯得較為無力招架,所以開發者們從最原初的 thunk 出發,開始尋求其他的解決方案。

處理 side effects 的其他 middleware 中較為亮眼的則有 redux-observable,與 redux-sage,基本上兩者處理 side effects 都非常優秀,並且相似,而這篇文章則是想要整理些比較做個筆記以及提供給各位做選擇上的參考。

那麼先從簡單的介紹開始切入核心:


以 RxJS 為主,核心概念為將 action 視為 stream,透過 observe action 並且轉換為另一個 action 來處理異步請求。

Actions in, actions out,在這邊附上從官方文件來的簡單範例

Rx 系列老話一句,什麼東西都 Observable。

而對 RxJS 並不熟悉的各位,Rx 系列的文件非常齊全,推薦可以透過 RxMarbles 的視覺化 Operator 來學習。

Netflix 工程師 Jay Phelps 的 talk 也非常有幫助,並且非常風趣 (Jay: open source的第一步,就是要做一個好 Logo)。
introduction

到這邊 Rx 的缺點:需要的入門門檻有點高就悄悄的冒出來了


以 ES6 generator 為核心主軸,利用 yield 和 redux saga 所提供的一些 helpers 來處理 async actions。

我們可以從官方的範例裡看到 generator 的運用,而學習 redux-saga 基本上就等同於學習 ES6 generator 的過程。

By doing so, these asynchronous flows look like your standard synchronous JavaScript code. (kind of like async/await, but generators have a few more awesome features we need)

不是我偏心,不對 redux-saga 提更多介紹,因為他的本體幾乎就是 generator。

Compare side by side

因為 redux-sage 或是 redux-observabl 其實兩者的差異並沒有到天差地遠的大,那就跟選用顯卡一樣各取所需,接下來就依照一些使用情境來讓各位能更清楚的了解兩者的差異。

Launch Up

saga - Watcher + Worker

observable - Type & Observable

Cancelable

saga

observable

Throttling

saga

observable

Debouncing

saga

observable

Retrying

saga

observable

Conclusion

redux-observable Redux-Saga
Learning Path
  • redux
  • Functional Programming
  • RxJS (ReactiveX)
  • redux-observable
  • redux
  • ES6 Generator
  • Redux-Saga
Style Declarative Imperative
Pros/Cons
  • 需要學習新的概念,例如 FP & ReactiveX,入門門檻高。
  • FP 的優點 Declarative 讓程式更可預測,易懂、好閱讀,同時也可以是缺點(chaining 像哈味一樣,有人喜歡有人不喜歡)
  • 習慣(中毒) Observable Pattern 之後可以將概念運用在各個地方,不單是 redux-observable,可以像是 Animation -
    [推薦閱讀,神一般的 CSS animation] Getting Reactive with CSS - David Khourshid
  • 實作 Generator 對熟悉 ES6 的開發者來說上手Redux-Saga 時間很短,只需要了解 Saga 提供的 helpers 與抽象概念 Effects 就行了。(但也有一說是不需要學習 Generator ,除非你是 lib or framework devloper - With ES7 And Beyond, Do You Need To Know ES6 Generators?
  • Imperative Programming 也跟 Declarative 一樣既是優點也是缺點,他是每一位開發者從小到大(?)熟悉的開發模式,但實作上相較 FP 來說更不可預期,需要時間理解,會有 state 變多所帶來的 Side Effects,但神人就是可以寫得很好

Thanks for the authorization from Chao wei Chiu. Side by side comparsion is an awesome presentation. (Here is the transcript)

另外有其他更棒的 side by side comparison 例子歡迎大家討論提供 😉