今天说说koa2中next的原理
举个栗子🌰
1 |
|
输出结果:
1 | // q |
分析栗子🌰
先看一张图
首先我们看到上面有黄色的模块,这个我们定义为我们刚刚使用的中间件默认执行函数callback(D),三个中间件一次为A、B、C,那么我们下面的两个条状柱体是reduceRight中reducer回调函数的前两个参数
那我们看到的应该是这样的。
第一次回调分别是D、C,因为我们后面传入了默认值D,第二次是返回第一次reducer返回的函数,第三次是返回第二次reducer返回的函数,以此类推,就生成了这个图。然后就形成了联调,那么最后拿到的q就是最后的A->B的函数,这样的话就形成链条(链表),然后我们顺着缕缕接下来的过程。A执行的时候,A里面包含next,而这个next正好是B,B执行的时候,B里面next正好是C,C执行的时候,C里面的next正好是D,好,这个时候D执行完,往上回溯,执行C的next后面的逻辑,这个时候C执行结束,到B的next后面逻辑,最后到A的next后面逻辑,最后就形成了这个神奇的next串
注:这里是没有考虑异步
直接koa2
上面是模拟koa2,下面直接使用koa2
1 | const Koa = require('koa'); |
输出结果:
1 | >> one |
当然这和我们的next放的位置有关系
放最后就不会出现回溯,最前面的话,表面看就只有回溯
如果打开上面return
则输出结果为:
1 | >> one |
这样的话可以阻止会面的回溯,通常也会这样写,当然也有特殊case中需要用到这个特性,比如
记录请求的总耗时
1 | app.use( (ctx, next) => { |
关于上面的运行机制及原理,我们分析一波
我们关注下application.js
application传送门
1 | use(fn) { |
重点关注this.middleware.push(fn)
,向我们的middleware栈push中间件
1 | callback() { |
重点关注const fn = compose(this.middleware)
和handleRequest中的return fnMiddleware(ctx).then(handleResponse).catch(onerror)
那重点就在compose,compose函数返回的是一个promise
1 | function compose (middleware) { |
我们重点关注这个dispatch
,这样结合上面的看会发现形成了一个递归链,这样也就解释了为什么会出现回溯
当next为空,直接返回,所以也就解释了为什么没有next不会向下走。
假设我们执行到第一个fn了,这个时候fn是
1 | fn = async (ctx, next) => { |
next
对应 function next(){return dispatch(i+1)}
,所以就进入到dispatch(i+1)
下一个中间件了,以此类推。
核心就是dispatch,最后结束就是next不存在,然后开始依次回溯到里层,所以执行顺序是越先注册越后执行。