一句话总结
Middleware就是增强了dispatch
开始调用createStore发生了什么
//调用const store = createStore(rootReducer, applyMiddleware(...middlewares));//createStoreexport 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 返回的结果可以解析为
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,dispatch
具体做了些什么
var middlewareAPI = { getState: store.getState, dispatch: (action) => dispatch(action)}chain = middlewares.map(middleware => middleware(middlewareAPI))dispatch = compose(...chain)(store.dispatch)复制代码
- 定义了一个对象(middlewareAPI) ,并将 store.state和store.dispatch绑定到这个对象中(都是引用)
- 然后循环这些中间件,并将middlewareAPI作为参数执行middleware,因为都是高级函数,所以返回的是next数组,并保存到chain中
- 最重要的是下一步的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))) 这一坨做了些什么?
reduce 是专门为累加操作设计的,啥意思呢
先把funcs.reduce((a, b) => (...args) => a(b(...args))) 翻译一下
- 假如说 funcs[a,b,c,d,e,f]
- 那么执行之后的结果就是a(b(c(d(e(f(...args)))
- 因为是compose(...chain)(store.dispatch)调用,所以...args就是store.dispatch,原生的dispatch,就是说最内层,调用的是原生的dispatch
- 这个有个洋葱模型,网上复制一个
所以最后返回的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 } }复制代码
- 从源码上可以分析出当执行chain = middlewares.map(middleware => middleware(middlewareAPI))时 直接返回了next()函数
- 当有一堆middleware时,执行middleware都返回一个next()函数
- 所以chain就是一个next()数组
- 而这个next()其实就是下一个middleware
- 一直next到最里面的执行store.dispatch
流程
- 调用applyMiddleware传入n个 middleware
- 用 middlewareAPI 保存了当前的store.state,store.dispatch(每个middleware共享)
- 迭代middlewares,执行每个middleware并携带middlewareAPI,返回一个next()
- 将chain整理成嵌套的函数,最里层调用store.dispatch
- 返回一个经过处理的dispatch
用一个最恶心的方式总结
//模拟三个middlewarefunction 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,然后由外向内执行.