Redux-Saga中間件剖析

前端時間一直在補大學(xué)的知識,很慚愧==,今天帶來一個項目中用的知識,目前的技術(shù)棧是ant design + dva + koa,至于dva是什么,下面是dva團隊的介紹:dva 是基于現(xiàn)有應(yīng)用架構(gòu) (redux + react-router + redux-saga 等)的一層輕量封裝。dva 是 framework,不是 library,類似 emberjs,會很明確地告訴你每個部件應(yīng)該怎么寫,這對于團隊而言,會更可控。另外,除了 react 和 react-dom 是 peerDependencies 以外,dva 封裝了所有其他依賴。dva 實現(xiàn)上盡量不創(chuàng)建新語法,而是用依賴庫本身的語法,比如 router 的定義還是用 react-router 的 JSX 語法的方式(dynamic config 是性能的考慮層面,之后會支持)。他最核心的是提供了app.model方法,用于把 reducer, initialState, action, saga 封裝到一起。

以后會專門找個時間詳細剖析下這個個人非常喜歡的輕量級框架,螞蟻金服把這套框架結(jié)合antd可能以及經(jīng)把中后臺開發(fā)方案提升到了一個更為高層級的水平,這個我們以后再說,今天主要是介紹我們的rudex中間件:saga

Redux-Saga

redux-saga 是一個用于管理 Redux 應(yīng)用異步操作(Side Effects。譯注:直譯成 “副作用” 不太通順,所以這里譯為 “異步操作” 更好理解)的中間件(又稱異步 action)。 redux-saga 通過創(chuàng)建Sagas將所有的異步操作邏輯收集在一個地方集中處理,可以用來代替redux-thunk中間件。

這意味著應(yīng)用的邏輯會存在兩個地方:

Reducers 負責(zé)處理 action 的 state 更新。

Sagas 負責(zé)協(xié)調(diào)那些復(fù)雜或異步的操作。

Sagas 是通過 Generator 函數(shù)來創(chuàng)建的。如果你還不熟悉 Generator,可以在這里找到一些有用的鏈接

Sagas 不同于 Thunks,Thunks 是在 action 被創(chuàng)建時調(diào)用,而 Sagas 只會在應(yīng)用啟動時調(diào)用(但初始啟動的 Sagas 可能會動態(tài)調(diào)用其他 Sagas)。 Sagas 可以被看作是在后臺運行的進程。Sagas 監(jiān)聽發(fā)起的 action,然后決定基于這個 action 來做什么:是發(fā)起一個異步調(diào)用(比如一個 Ajax 請求),還是發(fā)起其他的 action 到 Store,甚至是調(diào)用其他的 Sagas。

在redux-saga的世界里,所有的任務(wù)都通用 yieldEffects來完成(譯注:Effect 可以看作是 redux-saga 的任務(wù)單元)。Effects 都是簡單的 Javascript 對象,包含了要被 Saga middleware 執(zhí)行的信息(打個比方,你可以看到 Redux action 其實是一個個包含執(zhí)行信息的對象)。redux-saga為各項任務(wù)提供了各種 Effect 創(chuàng)建器,比如調(diào)用一個異步函數(shù),發(fā)起一個 action 到 Store,啟動一個后臺任務(wù)或者等待一個滿足某些條件的未來的 action。

因為使用了 Generator,redux-saga讓你可以用同步的方式寫異步代碼。就像你可以使用async/await函數(shù)所能做的一樣。但 Generator 可以讓你做一些async函數(shù)做不到的事情。

事實上 Sagas yield 普通對象的方式讓你能容易地測試 Generator 里所有的業(yè)務(wù)邏輯,可以通過簡單地迭代 yield 過的對象進行簡單的單元測試。

此外,redux-saga啟動的任務(wù)可以在任何時候通過手動取消,也可以把任務(wù)和其他的 Effects 放到 race 方法里以自動取消。

通俗點說,Redux-saga 是一個旨在于在React/Redux應(yīng)用中更好、更易地解決異步操作(action)的庫。主要模塊是 saga 會像一個分散的支線在你的應(yīng)用中單獨負責(zé)解決異步的action(類似于后臺運行的進程)。詳細移步:Redux-saga

redux-saga相當于在Redux原有數(shù)據(jù)流中多了一層,對Action進行監(jiān)聽,捕獲到監(jiān)聽的Action后可以派生一個新的任務(wù)對state進行維護(當然也不是必須要改變State,可以根據(jù)項目的需求設(shè)計),通過更改的state驅(qū)動View的變更。圖如下所示:

用過redux-thunk的人會發(fā)現(xiàn),redux-saga 其實和redux-thunk做的事情類似,都是可以處理異步操作和協(xié)調(diào)復(fù)雜的dispatch。不同點在于:

Sagas 是通過 Generator 函數(shù)來創(chuàng)建的,意味著可以用同步的方式寫異步的代碼

Thunks 是在 action 被創(chuàng)建時才調(diào)用,Sagas 在應(yīng)用啟動時就開始調(diào)用,監(jiān)聽action 并做相應(yīng)處理; (通過創(chuàng)建 Sagas 將所有的異步操作邏輯收集在一個地方集中處理)

啟動的任務(wù)可以在任何時候通過手動取消,也可以把任務(wù)和其他的 Effects 放到 race 方法里可以自動取消

入門demo

redux-saga-beginner-tutorial

$ git clone https://github.com/HelianXJ/redux-saga-beginner-tutorial.git

$ git checkout redux-tool-saga// 切到有redux tool的分支配合chorme 的 Redux DevTools 工具查看邏輯更清晰

$ npm i//下載依賴

$ npm run hello//先看項目文件中的hello sagas

啟動server成功后view-on:http://172.22.32.14:9966/

由于redux-saga是用ES6的Generators實現(xiàn)異步,incrementAsync 是一個 Generator 函數(shù),所以當我們在 middleware 之外運行它,會返回一個易預(yù)見的遍歷器對象, 這一點應(yīng)用在單元測試中更容易寫unit。

實際上 redux-saga 所有的任務(wù)都通用 yield Effects 來完成。它為各項任務(wù)提供了各種 Effect 創(chuàng)建器,可以是:

調(diào)用一個異步函數(shù)

發(fā)起一個 action 到 Store

啟動一個后臺任務(wù)或者等待一個滿足某些條件的未來的 action

Redux-Saga優(yōu)點

流程拆分更細,異步的action 以及特殊要求的action(更復(fù)雜的action)都在sagas中做統(tǒng)一處理,流程邏輯更清晰,模塊更干凈;

以用同步的方式寫異步代碼,可以做一些async 函數(shù)做不到的事情 (無阻塞并發(fā)、取消請求)

能容易地測試 Generator 里所有的業(yè)務(wù)邏輯

可以通過監(jiān)聽Action 來進行前端的打點日志記錄,減少侵入式打點對代碼的侵入程度

帶來的問題和可接受性

action 任務(wù)拆分更細,原有流程上相當于多了一個環(huán)節(jié)。對開發(fā)者的設(shè)計和抽象拆分能力更有要求,代碼復(fù)雜性也有所增加。

異步請求相關(guān)的問題較難調(diào)試排查

資歷尚淺,有不當之處還請指正

原文地址:https://juejin.im/post/58eb4100ac502e006c45d5c9

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容