资讯专栏INFORMATION COLUMN

Redux-Middleware-原理解析

ideaa / 390人阅读

摘要:再学习的过程中这块感觉很烧脑所以对它的原理进行整理有一些比较基础的先不整理以日志中间件为例以下的这种写法属于柯里化的知识以上的代码可以解释成源码假如说里有三个一个保存了状态和方法的对象这个对应的就是的通过闭包的形式引用外部的执行了方法返回了

再学习redux的过程中,Middleware这块感觉很烧脑,所以对它的原理进行整理

有一些比较基础的先不整理,

以日志中间件为例

//以下的这种写法属于柯里化的知识
const logger = state => next => action =>{
    console.log("dispatch", action);
    next(action);
    console.log("nextState",store.getState);
}

以上的代码可以解释成

var logger = function logger(state) {
    return function (next) {
        return function (action) {
            console.log("dispatch", action);
            next(action);
            console.log("nextState", store.getState);
        };
    };
};
//applyMiddleware 源码
export default function applyMiddleware(...middlewares) {
  //假如说 middlewares 里有三个mid1,mid2,mid3
  return (createStore) => (reducer, preloadedState, enhancer) => {
    const store = createStore(reducer, preloadedState, enhancer)
    let dispatch = store.dispatch
    let chain = []

    //一个保存了store状态,和dispatch方法的对象 这个对应的就是logger 的store
    const middlewareAPI = {
      getState: store.getState,
      dispatch: (action) => dispatch(action)//通过闭包的形式引用外部的dispatch
    }
    //执行了middleware方法,返回了需要next参数的方法 的数组
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    //假如chain 为[f1,f2,f3,f4,f5,f6,f7]
    //那么下面这句话的翻译就是这样   dispatch = f1(f2(f3(f4(f5(f6(f7(store.dispatch)))))))
    //就是将chain中的函数串联到一起,这种组合从最里面开始执行,返回的结果作为上一个函数的参数,一直向外执行
    //就是相当于从chain函数的最右侧到最左侧执行
    //compose(...chain) 返回的是一个匿名函数  function compose(...funcs)  funcs就是chain
    //return funcs.reduce((a, b) => (...args) => a(b(...args))) 这里的args就是store.dispatch
    dispatch = compose(...chain)(store.dispatch)
    //dispatch = f1(f2(f3(f4(f5(f6(f7(store.dispatch)))))))
    //当调用dispatch的时候就依次执行
    return {
      ...store,
      dispatch// 这个是处理过的dispatch
    }
  }

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

这里可以看出来,在日志中间件中的第一层的store就是middlewareAPI
并且将第二层返回到chain的数组中
这就相当于当初的store => next => action =>{...}变成了next => action =>{...}

dispatch = compose(...chain)(store.dispatch)

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)))
}

这一步相当于把chain数组中函数,通过处理得到一种类似于层层嵌套的结构f1(f2(f3(f4(args))))
所以dispatch = A(B(C(store.dispatch))

单个中间件较为简单,所以拿三个中间件做例子
经上面所述

//因为抛开store,剩下的中间件的结构类似于下面这种
function A1(next){
  return function A2(action){
    next(action)
  }
}

function B1(next){
  return function B2(action){
    next(action)
  }
}

function C1(next){
  return function C2(action){
    next(action)
  }
}
//dispatch = A(B(C(store.dispatch))
//这种结构会先执行最内部的函数,也就是C(store.dispatch)这一块
//当执行了C 返回的是一个函数
function C2(action){
    store.dispatch(action)
}

//返回值最为他的外层函数的参数next
next = function C2(action){
    store.dispatch(action)
}
//此时的结构类似于这种
dispatch = A(B(function C2(action) {
                    store.dispatch(action)
                }(action)
                )
            )
//接下来执行B,返回了
next = function C2(action){
    function C2(action){
        store.dispatch(action)
    }(action)
}
//此时的结构类似于这种
dispatch = A(function B2(action) {
                    function C2(action){
                        store.dispatch(action)
                    }(action)
                }(action)
            )
//接下来执行A,返回了
dispatch = function A2(action){
                function B2(action) {
                    function C2(action){
                        store.dispatch(action)
                    }(action)
                }(action)
            }(action)

最后返回新的store

总结

调用applyMiddleware 传入n个中间件的数组

用一个middlewareAPI保存当前的store.getState,和dispatch所指向的函数

迭代中间件数组,并执行一遍,将middlewareAPI作为最外层的store,并且返回一个相当于next函数的数组

将数组整理成嵌套的函数体,并将store.dispatch传入最内侧的函数的next,并返回经过处理的dispatch (dispatch是一个经过处理的函数,是一个嵌套了多层的函数,其最里面调用的是store.dispatch)

返回一个新的store

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/108025.html

相关文章

  • 浏览器工作原理整理

    摘要:每种可被解析的格式必须具有由词汇及语法规则组成的特定的文法,称为上下文无关文法。解析解析器,每个标识都有特定的正则进行解析。开发者可以将脚本标识为,以使其不阻塞文档解析,并在文档解析结束后执行。 浏览器组成 用户界面-地址栏、按钮之类的 浏览器引擎-用来查询及操作渲染引擎的接口 渲染引擎-显示请求的内容 网络-进行网络请求 ui后端-用来沪指选择框、对话框的基本组件 js解析器 数据...

    hqman 评论0 收藏0
  • 浏览器工作原理整理

    摘要:每种可被解析的格式必须具有由词汇及语法规则组成的特定的文法,称为上下文无关文法。解析解析器,每个标识都有特定的正则进行解析。开发者可以将脚本标识为,以使其不阻塞文档解析,并在文档解析结束后执行。 浏览器组成 用户界面-地址栏、按钮之类的 浏览器引擎-用来查询及操作渲染引擎的接口 渲染引擎-显示请求的内容 网络-进行网络请求 ui后端-用来沪指选择框、对话框的基本组件 js解析器 数据...

    Dionysus_go 评论0 收藏0
  • CDN工作原理

    摘要:通过以上四个步骤,浏览器完成从用户处接收用户要访问的域名到从域名服务主机处获取数据的整个过程。概念解析指别名记录也被称为规范名字可以理解为对域名设置别名。详细可以参考一些名词解释 传统的网络访问形式为: showImg(http://segmentfault.com/img/bVcqjG); 由上图可见,用户访问未使用CDN缓存网站的过程为: 用户向浏览器提供要访问的域名; 浏...

    zhonghanwen 评论0 收藏0
  • 【进阶3-5期】深度解析 new 原理及模拟实现

    摘要:使用指定的参数调用构造函数,并将绑定到新创建的对象。由构造函数返回的对象就是表达式的结果。情况返回以外的基本类型实例中只能访问到构造函数中的属性,和情况完全相反,结果相当于没有返回值。 定义 new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。 ——(来自于MDN) 举个栗子 function Car(color) { this.color = co...

    Baaaan 评论0 收藏0
  • JavaScript 工作原理之十四-解析,语法抽象树及最小化解析时间的 5 条小技巧

    摘要:事实是只是部分语言的不同表示法。基于这些,解析器会进行立即或者懒解析。然而,解析器做了完全不相关的额外无用功即解析函数。这里不解析函数,该函数声明了却没有指出其用途。所以之前的例子,解析器实际上 原文请查阅这里,本文采用知识共享署名 4.0 国际许可协议共享,BY Troland。 本系列持续更新中,Github 地址请查阅这里。 这是 JavaScript 工作原理的第十四章。 概...

    luqiuwen 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<