以上是整理的一些說明和文檔資料,沒有看過的能夠去了解一下。下面將開始本文的主題:redux的中間件applyMiddleware。前端
都說名字越長,越讓學者懼怕,applyMiddleware的名字看起來就挺嚇人,那麼爲何會出現中間件,它是作什麼的?它爲何叫中間件?爲何說能夠用來解決異步dispatch?通過一段時間的瞭解,讓我漸漸明白了它的工做原理,如今讓咱們帶問題,懷着簡單,輕鬆的心態走進applyMiddleware大講堂:react
console.log('dispatching', action);
dispatch(action)
假如又來一個產品B說,我須要記錄每次數據出錯的緣由,咱們怎麼辦呢?而後咱們又須要在對每個dispatch作修改git
try{ dispatch(action) }catch(err){ console.error('錯誤報告: ', err) }
若是咱們的程序中有不少的dispatch,咱們就須要添加不少的重複代碼,雖然編輯器提供批量替換,但這無疑是產生了不少樣板代碼。
由於全部的需求都是和dispatch息息相關,因此只要咱們把日誌放進dispatch函數裏,不就行了嗎,咱們只須要更改dispatch函數,把dispatch進行一層封裝。
大概的封裝就是下面這樣:
github
let next = store.dispatch store.dispatch = function dispatchAndLog(action) { console.log('dispatching', action) next(action) }
Redux把這個封裝的入口寫成了一個函數,就叫applyMiddleware。
由此咱們明白了applyMiddleware的功能:改造dispatch函數,產生真假dispatch,而中間件就是運行在假真(dispatchAndLog假和next真)之間的代碼。
這裏咱們要對applyMiddleware進行一個準確的定義,它只是一個用來加工dispatch的工廠,而要加工什麼樣的dispatch出來,則須要咱們傳入對應的中間件函數(好比上例中的dispatchAndLog),下面咱們構造一個精簡版的applyMiddleware:redux
const applyMiddleware = function(middleware){ let next = store.dispatch; store.dispatch = middleware(store)(next); // 這裏傳入store,是由於中間件中有可能會用到getState獲取數據,好比打印當前用戶等需求 } applyMiddleware(dispatchAndLog)
const logger = store => next => action => { console.log('dispatching', action) return next(action) } const collectError = store => next => action => { try { return next(action) } catch (err) { console.error('Error!', err) } }
而後,咱們改造一下applyMiddleware,來接收一個middlewares數組:數組
function applyMiddleware(middlewares) { middlewares = middlewares.slice() middlewares.reverse() let dispatch = store.dispatch middlewares.forEach(middleware => dispatch = middleware(store)(dispatch) ) return Object.assign({}, store, { dispatch }) }
上面的middleware(store)(dispatch) 就至關因而 const logger = store => next => {},這就是構造後的dispatch,繼續向下傳遞。這裏middlewares.reverse(),進行數組反轉的緣由,是最後構造的dispatch,其實是最早執行的。由於在applyMiddleware串聯的時候,每一箇中間件只是返回一個新的dispatch函數給下一個中間件,實際上這個dispatch並不會執行。只有當咱們在程序中經過store.dispatch(action),真正派發的時候,纔會執行。而此時的dispatch是最後一箇中間件返回的包裝函數。而後依次向前遞推執行。
咱們拿logger和collectError來講明:
構造過程:react-router
let next = store.dispatch; let dispatch1 = logger(store)(next); // 這時候的console.log('dispatching', action) 是沒有執行的 let dispatch2 = collectError(store)(dispatch1); // 這時候的console.log('Error!', err) 也是沒有執行的 store.dispatch = dispatch2;
執行過程:app
store.dispatch(action); //假如咱們程序中派發了某個action //至關因而下面這樣 dispatch2(action); //此時執行了 console.log('Error', err) //因爲collectError中間件中的next是接收的logger返回函數即dispatch1,因此在開始執行 dispatch1(action); //此時執行了 console.log('dispatching', action) // 這個例子不太合理,由於錯誤報告是先 try 的 next(action),可是正常的流程是如此。
未完待續……異步