一、Koa2中间件源码分析

在Koa2中,中间件被存放在一个数组中。 使用koa中,最常见的就是app.use(fn),use函数部分源码如下所示。首先中间件必须是个函数。若是generator函数,则需要进行转化。最后把该中间件推入middelaware数组中。

constructor() {this.middleware = [];
}
use(fn) {this.middleware.push(fn);
}
复制代码

当调用app.listen函数时,实际上是创建了一个原生http服务器,并执行了Koa自身的callback方法。

listen(...args) {const server = http.createServer(this.callback());return server.listen(...args);
}
复制代码

callback函数中compose是将中间件封装成一个迭代器,按照middleware数组中顺序执行下去,实现了面向切面编程。handleRequest函数则是将req和res封装成ctx,并执行中间件。

callback() {const fn = compose(this.middleware);const handleRequest = (req, res) => {const ctx = this.createContext(req, res);return this.handleRequest(ctx, fn);};return handleRequest;
}
handleRequest(ctx, fnMiddleware) {...return fnMiddleware(ctx).then(handleResponse).catch(onerror);
}
复制代码

compose用来返回一个迭代器函数fnMiddleware,该函数接受两个参数,context和next。因为调用时只向fnMiddleware传入了第一个参数context,所以next参数的值一直是undefined。

首先定义了index,dispatch传入的参数 i 作为每个中间件的调用标志,每次中间件调用next函数都会让index+1,若是中间件多次调用next,则会使index大于等于该标志,就会报错。

然后依次读取中间件数组中的中间件,并将context和封装了调用标志i的dispatch函数传给中间件,就实现了中间件的过程。
当读取完中间件数组后,即i === middleware.length时,将值为是undefined的next传给fn并结束迭代。dispatch函数所有的返回值都是Promise函数,这样就可以实现异步编程。

function compose (middleware) {return function (context, next) {// last called middleware #let index = -1return dispatch(0)function dispatch (i) {if (i <= index) return Promise.reject(new Error('next() called multiple times'))index = ilet fn = middleware[i]if (i === middleware.length) fn = nextif (!fn) return Promise.resolve()try {return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));} catch (err) {return Promise.reject(err)}}}
}
复制代码

二、Redux中间件源码分析

在Redux中需要引入中间件的话,需引入applyMiddleware函数并将其作为参数传给createStore。下方enhancer就是就是applyMiddleware的返回值。

export default function createStore(reducer, preloadedState, enhancer) {...return enhancer(createStore)(reducer, preloadedState)
}
复制代码

applyMiddleware接受一个中间件数组为参数。

export default function applyMiddleware(...middlewares) {return createStore => (...args) => {const store = createStore(...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}}
}
复制代码

其中compose用Array.prototype.reduce将中间件数组封装成一个层层包裹的函数。

function compose(...funcs) {return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
复制代码

若本来的中间件数组是

[a, b, c]

经过compose函数封装后,就成了

(...arg) => a(b(c(...arg)))

    dispatch = compose(...chain)(store.dispatch)
复制代码

经过这个过程后,每次调用dispatch就会在中间件中进行遍历。每个中间件都需要调用next(action)来保证中间件链都能被执行。

Redux中中间件的写法一般为

    const middleware = store => next => action => {...}
复制代码

根据上面的分析,store参数就是middlewareAPI,但是其中的dispatch并不是真正的dispatch,这是为了防止在中间件中调用store.dispatch而导致重新遍历整个中间件链。next是下一个中间件,需要传递action,直到最后一个中间件时,next即是原始的store.dispatch。

三、Koa2和Redux中间件比较

在两者中都出现了compose函数。
Koa2中的compose函数实现原理是用dispatch函数自身迭代,是从左向右执行中间件函数。而Redux中的compose实现原理是用了数组的reduce方法,从右向左执行中间件函数。两者执行顺序虽然不同,一样的是先执行的中间件可以获取后执行的中间件的状态(store的状态或者context的状态),实现了面向切面编程。

转载于:https://juejin.im/post/5b94b86c5188255c6a041c39

Koa2和Redux中间件源码研究相关推荐

  1. Redux 异步数据流-- thunk中间件源码解析

    Thunk 引入背景 这是一个关于Redux异步数据流的故事.引入thunk中间件的完整故事在Redux官方中文文档异步数据流.一句话总结就是:原生Redux只支持同步数据流,所以需要引入中间件(mi ...

  2. 一起谈.NET技术,.NET Framework源码研究系列之---万法归宗Object

    经过前面三篇关于.NET Framework源码研究系列的随笔,相信大家都发现其实.NET Framework的实现其实并不复杂,也许跟我们自己做的项目开发差不多.本人也是这样的看法.不过,经过仔细深 ...

  3. Apache Jackrabbit源码研究(五)

    上文最后提到jackrabbit的检索默认实现类QueryImpl,先熟悉一下该类的继承层次 QueryImpl继承自抽象类AbstractQueryImpl,而抽象类实现了Query接口(JCR的接 ...

  4. Nginx源码研究之nginx限流模块详解

    这篇文章主要介绍了Nginx源码研究之nginx限流模块详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考.一起跟随小编过来看看吧 高并发系统有三把利器:缓存.降级和限流: 限流的目的是通过对并 ...

  5. 转载一篇《Redis源码研究—哈希表》重点是如何重新哈希

    <Redis源码研究-哈希表>来自:董的博客 网址:http://dongxicheng.org/nosql/redis-code-hashtable/ 转载于:https://www.c ...

  6. underscore.js源码研究(5)

    概述 很早就想研究underscore源码了,虽然underscore.js这个库有些过时了,但是我还是想学习一下库的架构,函数式编程以及常用方法的编写这些方面的内容,又恰好没什么其它要研究的了,所以 ...

  7. 解析多层list_基于laravel5.2进行中间件源码的解析

    在laravel5.2中,Http的主要作用就是过滤Http请求(php aritsan是没有中间件机制的),同时也让系统的层次(Http过滤层)更明确,使用起来也很优雅.但实现中间件的代码却很复杂, ...

  8. WebRTC源码研究(4)web服务器工作原理和常用协议基础

    文章目录 WebRTC源码研究(4)web服务器工作原理和常用协议基础 前言 做WebRTC 开发为啥要懂服务器开发知识 1. Web 服务器简介 2. Web 服务器的类型 3. Web 服务器的工 ...

  9. WebRTC源码研究(47)WebRCT传输非音视频数据

    文章目录 WebRTC源码研究(47)WebRCT传输非音视频数据 WebRTC源码研究(47)WebRCT传输非音视频数据

最新文章

  1. 《水泥公司信息管理系统》Access学习心得
  2. shell练习03 安装mysql
  3. 第一篇 webApp启航
  4. 在日志中搜索时间间隔
  5. linux perl的while循环中ctrl+c失效,perl循环控制
  6. 非root用户安装protobuf的python依赖到指定目录
  7. 物联网卡对企业设备的重要性
  8. 物联网开发- Arduino 101/Genuino 101
  9. IDEA集成SVN客户端
  10. 【Flutter 问题系列第 26 篇】给 TextField 添加背景色,为什么没有效果 ?
  11. 【C语言】有n个人围成一圈,顺序排号。从第1个人开始报数(从1到3报数),凡报到3的人退出,问最后留下的人是原来第几号。
  12. 成功项目经理的能力提升
  13. 卡西欧计算器说明书获取方法
  14. tomcat+nginx配置htpps
  15. 南京市城乡地籍信息一体化管理的几点思考
  16. .cfg\.dat\.mak(持续补充)
  17. DWcs4右下角没有html文件,Dreamweaver cs4 cs5 spry菜单栏使用教程 详细教程 超好珍藏...
  18. 《华为区块链白皮书》重磅发布(4大类应用场景/5分钟上链/)
  19. 2022-04-28:有 n 个城市通过一些航班连接。给你一个数组 flights ,其中 flights[i] = [fromi, toi, pricei] ,表示该航班都从城市 fromi 开始,
  20. 天邑ty1208z海思3798刷版本_[FJ]安徽电信天邑ty1208z_mv100机顶盒刷全网通教程

热门文章

  1. 非对称加密算法之RSA介绍及OpenSSL中RSA常用函数使用举例
  2. MySQL中定义fk语句_MySQL基础篇/第3篇:MySQL基本操作语句.md · qwqoo/MySQL-Review - Gitee.com...
  3. mysql实现sass_使用sass绘制三角形
  4. 3dcaptcha php,验证simple-php-captcha()输入
  5. Java学习总结:5
  6. Java项目:仿小米电子产品售卖商城系统(java+SpringBoot+Vue+MySQL+Redis+ElementUI)
  7. Java项目:无库版商品管理系统(java+Gui+文档)
  8. 【matlab】第二章基本使用方法
  9. Hbase的过滤器查询
  10. 制作模拟器和真机通用静态库