美文网首页
关于redux中的Middleware

关于redux中的Middleware

作者: 7天苹果 | 来源:发表于2017-05-20 16:36 被阅读127次

    什么是Redux中间件 ?

    redux 提供了类似后端 Express 的中间件概念,本质的目的是提供第三方插件的模式,自定义拦截 action -> reducer 的过程。变为 action -> middlewares -> reducer 。redux中的中间件可以使得在用户调用store.dispatch之后,先对参数state和actions进行预处理,再让真正的store.dispatch调用,以确保reducer的纯度(函数式编程的概念)不变。


    applyMiddleware源码分析

    下面是 applyMiddleware 完整的代码,参数为 middlewares 数组:

    
    
    import compose from './compose'
    
    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
        }
      }
    }
    

    1.applyMiddleware 执行过后返回一个闭包函数,目的是将创建 store的步骤放在这个闭包内执行,这样 middleware 就可以共享 store 对象。

    2.middlewares 数组 map 为新的 middlewares 数组,包含了 middlewareAPI

    3.compose 方法将新的 middlewares 和 store.dispatch 结合起来,生成一个新的 dispatch 方法

    4.返回的 store 新增了一个 dispatch 方法, 这个新的 dispatch 方法是改装过的 dispatch,也就是封装了中间件的执行。

    所以关键点来到了 compose 方法了,下面来看一下 compose 的设计:

    export default 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)
      return (...args) => rest.reduceRight((composed, f) => f(composed), last(...args))
    

    可以看到 compose 方法实际上就是利用了 Array.prototype.reduceRight 。如果对 reduceRight 不是很熟悉,来看看下面的一个例子就清晰了:

    [0, 1, 2, 3, 4].reduceRight(function(previousValue, currentValue, index, array) {
      return previousValue + currentValue;
    }, 10);
    

    执行结果:

    执行结果

    理解中间件的执行过程

    通过上面的 applyMiddleware 和 中间件的结构,假设应用了如下的中间件: [A, B, C],一个 action 的完整执行流程:

    初始化阶段:

    一个中间件的结构:

    function ({getState}) {
        return function (next) {
            return function (action) {...}
        }
    }
    

    初始化阶段一:middlewares map 为新的 middlewares

    chain = middlewares.map(middleware => middleware(middlewareAPI))
    

    执行过后,middleware 变为了

    function (next) {
        return function (action) {...}
    }
    

    初始化阶段二:compose 新的 dispatch

    const newDispatch = compose(newMiddlewares)(store.dispatch)
    

    dispatch 的实现为 reduceRight, 当一个新的 action 来了过后

    /**
     * 1. 初始值为: lastMiddleware(store.dispatch)
     * 2. previousValue: composed
     * 3. currentValue: currentMiddleware
     * 4. return value: currentMiddleware(composed) => newComposed
     */
    rest.reduceRight((composed, f) => f(composed), last(...args))
    

    composed 流程

    初始时候

    initialValue: composedC = C(store.dispatch) = function C(action) {}
    
    next 闭包: store.dispatch
    

    第一次执行:

    previousValue(composed): composedC
    
    currentValue(f): B
    
    return value: composedBC = B(composedC) = function B(action){}
    
    next 闭包 composedC
    

    第二次执行:

    previousValue(composed): composedBC
    
    currentValue(f): A
    
    return value: composedABC = A(composedBC) = function A(action){}
    
    next 闭包 composedBC
    
    最后的返回结果为 composedABC
    

    执行阶段

    dispatch(action) 等于 composedABC(action) 等于执行 function A(action) {...}

    在函数 A 中执行 next(action), 此时 A 中 next 为 composedBC,那么等于执行 composedBC(action) 等于执行function B(action){...}

    在函数 B 中执行 next(action), 此时 B 中 next 为 composedC,那么等于执行 composedC(action) 等于执行function C(action){...}

    在函数 C 中执行 next(action), 此时 C 中 next 为 store.dispatch 即 store 原生的 dispatch, 等于执行store.dispatch(action)

    store.dispatch 会执行 reducer 生成最新的 store 数据

    所有的 next 执行完过后开始回溯

    执行函数 C 中 next 后的代码

    执行函数 B 中 next 后的代码

    执行函数 A 中 next 后的代码

    整个执行 action 的过程为 A -> B -> C -> dispatch -> C -> B -> A

    相关文章

      网友评论

          本文标题:关于redux中的Middleware

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