博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Redux-Middleware-源码解析
阅读量:5924 次
发布时间:2019-06-19

本文共 3879 字,大约阅读时间需要 12 分钟。


一句话总结

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)复制代码
  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))) 这一坨做了些什么?

reduce 是专门为累加操作设计的,啥意思呢

先把funcs.reduce((a, b) => (...args) => a(b(...args))) 翻译一下

  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. 这个有个洋葱模型,网上复制一个

所以最后返回的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

用一个最恶心的方式总结

//模拟三个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,然后由外向内执行.

转载地址:http://ogivx.baihongyu.com/

你可能感兴趣的文章
29.Flutter与原生解耦式混合开发
查看>>
编码 GBK 的不可映射字符
查看>>
广平县北方计算机第一届PS设计大赛
查看>>
oracle创建dblink
查看>>
smartctl---查看硬件接口
查看>>
深入理解Java的接口和抽象类
查看>>
fail2ban 帮助postfix 过滤恶意IP
查看>>
Simple Proxy Server (Java)
查看>>
Kafka消费的几种方式--low-level SimpleConsumer
查看>>
解决mysql数据库不能支持中文的问题
查看>>
VMware14虚拟机秘钥
查看>>
JVM -verbose参数详解
查看>>
CentOS LInux启动关闭和服务管理
查看>>
Eclipse中10个最有用的快捷键组合
查看>>
java与xml
查看>>
Redis Sentinel机制与用法(二)
查看>>
ls命令实际使用
查看>>
磁盘及磁盘阵列系统选择
查看>>
Javascript异步数据的同步处理方法
查看>>
9. Palindrome Number(回文数)(leetcode)
查看>>