Koa2和Redux中间件源码研究
一、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中间件源码研究相关推荐
- Redux 异步数据流-- thunk中间件源码解析
Thunk 引入背景 这是一个关于Redux异步数据流的故事.引入thunk中间件的完整故事在Redux官方中文文档异步数据流.一句话总结就是:原生Redux只支持同步数据流,所以需要引入中间件(mi ...
- 一起谈.NET技术,.NET Framework源码研究系列之---万法归宗Object
经过前面三篇关于.NET Framework源码研究系列的随笔,相信大家都发现其实.NET Framework的实现其实并不复杂,也许跟我们自己做的项目开发差不多.本人也是这样的看法.不过,经过仔细深 ...
- Apache Jackrabbit源码研究(五)
上文最后提到jackrabbit的检索默认实现类QueryImpl,先熟悉一下该类的继承层次 QueryImpl继承自抽象类AbstractQueryImpl,而抽象类实现了Query接口(JCR的接 ...
- Nginx源码研究之nginx限流模块详解
这篇文章主要介绍了Nginx源码研究之nginx限流模块详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考.一起跟随小编过来看看吧 高并发系统有三把利器:缓存.降级和限流: 限流的目的是通过对并 ...
- 转载一篇《Redis源码研究—哈希表》重点是如何重新哈希
<Redis源码研究-哈希表>来自:董的博客 网址:http://dongxicheng.org/nosql/redis-code-hashtable/ 转载于:https://www.c ...
- underscore.js源码研究(5)
概述 很早就想研究underscore源码了,虽然underscore.js这个库有些过时了,但是我还是想学习一下库的架构,函数式编程以及常用方法的编写这些方面的内容,又恰好没什么其它要研究的了,所以 ...
- 解析多层list_基于laravel5.2进行中间件源码的解析
在laravel5.2中,Http的主要作用就是过滤Http请求(php aritsan是没有中间件机制的),同时也让系统的层次(Http过滤层)更明确,使用起来也很优雅.但实现中间件的代码却很复杂, ...
- WebRTC源码研究(4)web服务器工作原理和常用协议基础
文章目录 WebRTC源码研究(4)web服务器工作原理和常用协议基础 前言 做WebRTC 开发为啥要懂服务器开发知识 1. Web 服务器简介 2. Web 服务器的类型 3. Web 服务器的工 ...
- WebRTC源码研究(47)WebRCT传输非音视频数据
文章目录 WebRTC源码研究(47)WebRCT传输非音视频数据 WebRTC源码研究(47)WebRCT传输非音视频数据
最新文章
- 《水泥公司信息管理系统》Access学习心得
- shell练习03 安装mysql
- 第一篇 webApp启航
- 在日志中搜索时间间隔
- linux perl的while循环中ctrl+c失效,perl循环控制
- 非root用户安装protobuf的python依赖到指定目录
- 物联网卡对企业设备的重要性
- 物联网开发- Arduino 101/Genuino 101
- IDEA集成SVN客户端
- 【Flutter 问题系列第 26 篇】给 TextField 添加背景色,为什么没有效果 ?
- 【C语言】有n个人围成一圈,顺序排号。从第1个人开始报数(从1到3报数),凡报到3的人退出,问最后留下的人是原来第几号。
- 成功项目经理的能力提升
- 卡西欧计算器说明书获取方法
- tomcat+nginx配置htpps
- 南京市城乡地籍信息一体化管理的几点思考
- .cfg\.dat\.mak(持续补充)
- DWcs4右下角没有html文件,Dreamweaver cs4 cs5 spry菜单栏使用教程 详细教程 超好珍藏...
- 《华为区块链白皮书》重磅发布(4大类应用场景/5分钟上链/)
- 2022-04-28:有 n 个城市通过一些航班连接。给你一个数组 flights ,其中 flights[i] = [fromi, toi, pricei] ,表示该航班都从城市 fromi 开始,
- 天邑ty1208z海思3798刷版本_[FJ]安徽电信天邑ty1208z_mv100机顶盒刷全网通教程
热门文章
- 非对称加密算法之RSA介绍及OpenSSL中RSA常用函数使用举例
- MySQL中定义fk语句_MySQL基础篇/第3篇:MySQL基本操作语句.md · qwqoo/MySQL-Review - Gitee.com...
- mysql实现sass_使用sass绘制三角形
- 3dcaptcha php,验证simple-php-captcha()输入
- Java学习总结:5
- Java项目:仿小米电子产品售卖商城系统(java+SpringBoot+Vue+MySQL+Redis+ElementUI)
- Java项目:无库版商品管理系统(java+Gui+文档)
- 【matlab】第二章基本使用方法
- Hbase的过滤器查询
- 制作模拟器和真机通用静态库