Redux-Middleware-源碼解析

image


一句話總結

Middleware就是加強了dispatch


開始調用createStore發生了什麼

//調用
const store = createStore(rootReducer, applyMiddleware(...middlewares));
//createStore
export default function createStore(reducer, preloadedState, enhancer) //若是第二個參數是function,而且沒傳第三個參數,則將第二個參數賦值給第三個參數,而後將第二個參數設爲undefined if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
    enhancer = preloadedState
    preloadedState = undefined
  }

  if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
      throw new Error('Expected the enhancer to be a function.')
    }
    //返回一個高階函數
    return enhancer(createStore)(reducer, preloadedState)
  }
} 
複製代碼

經過調用createStore 返回的結果能夠解析爲javascript

applyMiddleware(...middlewares)(createStore)(reducer, initialState)
複製代碼

applyMiddleware源碼裏發生了什麼

//調用applyMiddleware,能夠傳入多箇中間件
export default function applyMiddleware(...middlewares) {
  return (createStore) => (reducer, initialState, enhancer) => {
    var store = createStore(reducer, initialState, enhancer)

    var dispatch = store.dispatch
    var chain = []
    //將state和dispatch所指向的函數綁定到middlewareAPI
    var middlewareAPI = {
      getState: store.getState,
      dispatch: (action) => dispatch(action)
    }
    //迭代中間件數組,並執行一遍,將middlewareAPI做爲最外層的store,並返回一個至關於next函數的數組
    chain = middlewares.map(middleware => middleware(middlewareAPI))

    //將數組整理成嵌套的函數體,並將store.dispatch傳入最內側的函數的next,並返回通過處理的dispatch
    //dispatch是一個函數,是一個嵌套了多層的函數,其最裏面調用的是store.dispatch
    dispatch = compose(...chain)(store.dispatch)
    //返回一個新的store
    return {
      ...store,
      dispatch
    }
  }
}
複製代碼

大體看下,其實就是經過一些操做,而後返回一個通過處理的store,dispatchjava

具體作了些什麼

var middlewareAPI = {
    getState: store.getState,
    dispatch: (action) => dispatch(action)
}
chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)

複製代碼
  1. 定義了一個對象(middlewareAPI) ,並將 store.state和store.dispatch綁定到這個對象中(都是引用)
  2. 而後循環這些中間件,並將middlewareAPI做爲參數執行middleware,由於都是高級函數,因此返回的是next數組,並保存到chain中
  3. 最重要的是下一步的compose函數
export default function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }
  if (funcs.length === 1) {
    return funcs[0]
  }
  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
複製代碼

這裏有必要解釋下funcs.reduce((a, b) => (...args) => a(b(...args))) 這一坨作了些什麼?redux

reduce 是專門爲累加操做設計的,啥意思呢數組

先把funcs.reduce((a, b) => (...args) => a(b(...args))) 翻譯一下app

  1. 假如說 funcs[a,b,c,d,e,f]
  2. 那麼執行以後的結果就是a(b(c(d(e(f(...args)))
  3. 由於是compose(...chain)(store.dispatch)調用,因此...args就是store.dispatch,原生的dispatch,就是說最內層,調用的是原生的dispatch
  4. 這個有個洋蔥模型,網上覆制一個
    image

因此最後返回的dispatch是通過處理的dispatch:a(b(c(d(e(f(store.dispatch)))


解釋下chain是什麼?

//以redux-saga爲例
  //看參數,就知道爲何定義middlewareAPI對象了
  function sagaMiddleware({ getState, dispatch }) {
    ...
    return next => action => {
      if (sagaMonitor && sagaMonitor.actionDispatched) {
        sagaMonitor.actionDispatched(action)
      }
      const result = next(action) // hit reducers
      channel.put(action)
      return result
    }
  }
複製代碼
  1. 從源碼上能夠分析出當執行chain = middlewares.map(middleware => middleware(middlewareAPI))時 直接返回了next()函數
  2. 當有一堆middleware時,執行middleware都返回一個next()函數
  3. 因此chain就是一個next()數組
  4. 而這個next()其實就是下一個middleware
  5. 一直next到最裏面的執行store.dispatch

流程

  1. 調用applyMiddleware傳入n個 middleware
  2. 用 middlewareAPI 保存了當前的store.state,store.dispatch(每一個middleware共享)
  3. 迭代middlewares,執行每一個middleware並攜帶middlewareAPI,返回一個next()
  4. 將chain整理成嵌套的函數,最裏層調用store.dispatch
  5. 返回一個通過處理的dispatch

用一個最噁心的方式總結

//模擬三個middleware
function A(next){
    return function A1(action){
        next(action)
    }
}
function B(next){
    return function B1(action){
        next(action)
    }
}
function C(next){
    return function C1(action){
        next(action)
    }
}
複製代碼

假設 dispatch = A(B(C(store.dispatch))),開始執行函數

function A1(action){
    function B1(action){
        return function C1(action){
            store.dispatch(action)
        }
    }
}(action)
複製代碼

一個action的執行順序:A(action) -> B(action) -> C(action) -> store.dispatch(action),先從內到外生成新的func,而後由外向內執行.ui

相關文章
相關標籤/搜索