一、开始
首先我们来看下面这段代码:
const Koa = require("koa");
const app = new Koa();
app.use( (ctx, next) => {
console.log(1);
next();
console.log(2);
});
app.use( (ctx, next) => {
console.log(3);
next();
console.log(4);
});
app.use( (ctx, next) => {
console.log(5);
next();
console.log(6);
});
app.listen(3000);
按照正常的逻辑是输出是:1,2,3,4,5,6;但是根据koa的执行逻辑输出是:1,3,5,6,4,2;这种输出逻辑叫做洋葱模型(个人粗浅总结),下面我们就来实现实现这种输出逻辑。
二、实现
- 定义用来存函数的数组middlewares,定义用来将函数存入数组的函数use
const app = {
middlewares: [],// 用来存函数的数组
use: function (fn) {
// 将app.use中传入的实参(函数)存入数组
this.middlewares.push(fn);
}
}
- 执行use函数,开始将use中的实参(函数)存入数组middlewares中
app.use((next) => {
console.log(1);
next();
console.log(2);
});
app.use((next) => {
console.log(3);
next();
console.log(4);
});
app.use((next) => {
console.log(5);
next();
console.log(6);
});
- 递归执行数组中的函数
// 定义compose函数来递归执行middlwares中的函数,也可以定义其他函数名称,koa中定义的是compose,这里我们也定义compose函数
app.compose = function () {
// 这里也可以不用返回一个函数,为了模拟koa的逻辑
return function () {
// 定义dispatch用来执行middlewares中的函数
function dispatch(idx) {
// 如果idx等于app.middlewares.length,则return掉
if (idx === app.middlewares.length) {
return;
}
// 从middlewares中取函数
const fn = app.middlewares[idx];
// 执行第一个app.use传入的实参(函数),并且传入实参next
fn(function next() {
// 在dispatch(1)中将会执行next中执行下一个app.use传入的实参(函数),开始递归
dispatch(++idx);
});
}
// 传入0,开始执行middlewares中的第一个函数,即执行app.use中传入的第一个函数
dispatch(0);
};
};
app.compose()();
三、总结
- next函数即下一个app.use中传入的函数;
- 第三个app.use的next函数,会因为idx等于app.middlewares.length直接return掉;
- 所以接下来会执行console.log(6);执行完console.log(6),即第二个app.use中的next函数已执行完,所以会往下执行则执行console.log(4);
- 当console.log(4)执行完,则表示第一个app.use中next函数已执行完;
- 所以会往下执行,执行console.log(2),执行完console.log(2),所有代码全部执行完成,完结撒花~