[源码阅读]redux的中间件源码阅读

190 阅读4分钟

前言

源码

redux-middleware.png

Redux.applyMiddleWare()

他其实做的就是,用于增减store

首先看一下用法,中间件可以作为createStore()第二个或者第三个参数传进去

var store = Redux.createStore(counter, Redux.applyMiddleware(logger1))
//或者
var store = Redux.createStore(counter, preState,Redux.applyMiddleware(logger1))

那么上面那篇文章只是减少了createStore里面的几个函数,那么我们现在来看一下需要的形参

function createStore(reducer, preloadedState, enhancer) {
  //省略一下判断
  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接受三个参数

  • reducer:就是那个接受actionpreState的函数,返回新的state
  • preloadedState:state
  • enhancer:我们传入中间件的地方

从最后一行代码看出,当我们传入中间件的时候,我们就会去调用这个enhancer(createStore)(reducer, preloadedState)函数

enhancer--中间件函数

当我们打断点的时候,发现其实,他先执行的是applyMiddleware()这个函数,在这个函数里面去调用createStore函数,至于为什么,我们可以理解为,执行栈问题

  • 首先Redux.createStore()入栈
  • 在这个里面因为调用了applyMiddleware(),所以applyMiddleware()入栈
  • applyMiddleWare()执行完成,出栈,所有,执行createStore

如果你感到困惑,我们可以在createStore.js里面输出调试一下

enhancer:里面是啥

console.log("enhancer",enhancer)

createStore调试.png

其实这里的createStore()不是那个createStore():Redux里的createStore函数,只是同名而已

那么我们现在来好好看一下这个代码enhancer(createStore)(reducer, preloadedState)

  • 首先肯定是调用了enhancer()这个函数,也就是那个createStore()函数(这边我改名为createStore1
export default function applyMiddleware(...middlewares) {
  console.log("middleWares",...middlewares);
  return createStore1 => (...args) => {
    console.log("args11",args);
    const store = createStore1(...args)
    let dispatch = () => {
      throw new Error(
        'Dispatching while constructing your middleware is not allowed. ' +
          'Other middleware would not be applied to this dispatch.'
      )
    }

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

    return {
      ...store,
      dispatch
    }
  }
}

我们来分析一下,执行栈里面

  • 首先,enhancer(createStore)enhancer函数入栈

    • 从上面我们可以知道enhancer其实就是createStore1()这个函数
    • 观察createStore1(),其实是一个箭头函数,返回值还是一个函数
  • 因为后面继续调用了函数enhancer(createStore)(reducer, preloadedState)

    • 所以调用了createStore1()返回的函数,并且传入参数reducerpreloadedState

    • 因为enhancer()传入了参数createStore,然后函数调用,其实createStore就是createStore1

    • const store = createStore1(...args)的时候又去执行了Redux.createStore(),并且将参数带过去

    • 因为参数使redcerperloadedState args参数.png

    • 所以createStore的参数也就变为了reducer, preloadedState, enhancer

      • reducer:function
      • preloadedState:undefined
      • enhancer:undefined
    • 这样我们这个store就拥有了getstate()dispatch()方法,那么我们createStore()方法

      • return {dispatch,getState...},那么,我们createStore1这个函数出栈,继续往下执行
      • 那么继续往下执行那个箭头函数(...args)=>{}
    • const chain = middlewares.map(middleware => middleware(middlewareAPI)),这里面是很多个中间件函数

      • 他们都有一个参数middleWareAPI,再去执行logger1这个中间件函数
  • 其实增强的dispatch()函数,则是用dispatch = compose(...chain)(store.dispatch)执行的

redux.compose()

用于组合传入的函数

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)))
    return funcs.reduce(function(a, b){
  		return function(...args){
    		return a(b(...args));
  			};
	}
  );
}

箭头函数并没有那么好理解,我们可以将箭头函数变为普通函数

arr.reduce()

这其实就是一个累加器,他将数组的每个值从左往右的开始缩减,最终计算为一个值

reducer()里面会放入一个函数,就是希望当前数组的变为什么样子的数组

我们可以件源码改变一下

export default function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }

  if (funcs.length === 1) {
    return funcs[0]
  }
  const composing = (a, b) => {
    console.log("a", a)
    console.log("b", b)
    return (...args) => {
      console.log("composing_args",args)
      return a(b(...args))
    }
  }
  return funcs.reduce(composing)
}

假设我们现在compose(f,g,h)

  • 最开始数组是[f,g,h]
  • 从左往右执行,第一次过后,数组变为[f(g()),h]
  • 第二次变为了[f(g(h()))]

源码的意思:

也就是每次都在外层添加一个函数,就是件这个函数的返回值作为参数传给另一个参数

那么我们现在返回的结果其实就是:一个正常的Store和一个被变更过的dispatch方法

总结

上次夸下海口说:11.5号就看完中间件这部分,奈何行动力太差了,兜兜转转到今天才把中间件看完。

reduxmiddleware适用于增强dispatch出现的

感觉对redux没有那么迷惑了

但是后续还是需要再好好了解一下,因为,感觉才只懂了一点皮毛🤦‍♀️

参考链接:Redux从设计到源码 - 美团技术团队 (meituan.com)