美文网首页
redux中的middleware解析

redux中的middleware解析

作者: 杨慧莉 | 来源:发表于2017-05-22 14:10 被阅读0次

    为什么需要middleware

    在没有middleware之前,Redux的工作流程是这样的


    上图表达的是redux 中一个简单的同步数据流动的场景
    面对多种多样的业务需求,单纯的修改 dispatchreducer的代码显然不具有普世性,我们需要的是可以组合的,自由插拔的插件机制。 另外,reducer更关心的是数据的转化逻辑,所以 reduxmiddleware 是为了增强 dispatch 而出现的

    上面这张图展示了应用 middlewareredux 处理事件的逻辑,每一个 middleware处理一个相对独立的业务需求,通过串联不同的 middleware,实现变化多样的的功能

    理解middleware机制

    1. 函数式编程思想设计 middleware

    易串联。柯里化函数具有延迟执行的特性,通过不断柯里化形成的 middleware可以累积参数,配合组合的方式,很容易形成 pipeline 来处理数据流
    共享store。在 applyMiddleware 执行过程中,store 还是旧的,但是因为闭包的存在,applyMiddleware完成后,所有的 middlewares内部拿到的 store 是最新且相同的

    2. 给 middleware 分发 store
    let newStore = applyMiddleware(mid1, mid2, mid3, ...)(createStore);
    
    
    3. 组合串联 middlewares
    dispatch = compose(...chain)(store.dispatch);
    

    applyMiddleware 源码分析

    export default function applyMiddleware(...middlewares) {
      return (createStore) => (reducer, preloadedState, enhancer) => {
        var store = createStore(reducer, preloadedState, enhancer)
        var dispatch = store.dispatch
        var chain = []
    
        var middlewareAPI = {
          getState: store.getState,
          dispatch: (action) => dispatch(action)
        }
        chain = middlewares.map(middleware => middleware(middlewareAPI))
        dispatch = compose(...chain)(store.dispatch)
        return {
          ...store,
          dispatch
        }
      }
    }
    
    • 通过...middlewares将所有的中间件存入到middlewares数组中
    • middlewares数组通过 map 方法执行生成新的middlewares数组且每一项都传入middlewareAPI,传入middlewareAPI的目的就使得每个中间件都可以访问到store,这时候middlewares数组的每一项都变为了
    function (next) {
        return function (action) {...}
    }
    
    • compose方法将新的 middlewaresstore.dispatch结合起来,生成一个新的 dispatch 方法
      我们这里可以来模拟一下compose函数处理完的结果,假设我们这边有两个中间件A和B,则传入到composefunc为[A, B],且A、B的形式已经是(next) => (action) => {}
    function A(next) {
        console.log('A...next === ', next)
        return function(action) {
            console.log('A...action')
            next(action)
        }
    }
    function B(next) {
        console.log('B...next === ', next)
        return function(action) {
            console.log('B...action')
            next(action)
        }
    }
    function compose(funcs) {
      if (funcs.length === 0) {
        return arg => arg
      }
      if (funcs.length === 1) {
        return funcs[0]
      }
      const last = funcs[funcs.length - 1]
      const rest = funcs.slice(0, -1)
      const fn = (args) => rest.reduceRight((composed, f) => f(composed), last(args))
      return fn
    }
    var fnArr = [A, B]
    var dispatch = compose(fnArr)("store.dispatch")
    console.log('new dispatch === ', dispatch)
    

    执行的结果是:


    由结果可以看到中间件A的next是指向中间件B的最内层闭包函数,而中间件B的next则是指向原生的dispatch,所以通过compose执行完后,所有的中间件就通过next串联起来了
    • 返回的 store 新增了一个 dispatch方法, 这个新的 dispatch 方法是改装过的 dispatch

    总结

    applyMiddleware 机制的核心在于组合 compose,将不同的 middlewares 一层一层包裹到原生的 dispatch 之上,而为了方便进行 compose,需对 middleware 的设计采用柯里化 curry 的方式,达到动态产生next 方法以及保持store 的一致性。由于在 middleware中,可以像在外部一样轻松访问到 store, 因此可以利用当前 storestate 来进行条件判断,用 dispatch 方法拦截老的 action或发送新的 action


    参考资料

    http://www.cnblogs.com/canfoo/p/6119446.html
    http://div.io/topic/1530
    https://zhuanlan.zhihu.com/p/20597452
    http://cn.redux.js.org/docs/advanced/Middleware.html

    相关文章

      网友评论

          本文标题:redux中的middleware解析

          本文链接:https://www.haomeiwen.com/subject/cnwvxxtx.html