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

相关文章
相关标签/搜索