Koa
koa
一、洋葱模型

二、洋葱模型原理
洋葱模型可以理解成函数嵌套调用。
在 koa
中,中间件被 next()
方法分成了两部分。next()
方法上面部分会先执行,下面部分会在后续中间件执行全部结束之后再执行。
原理模拟:
function A(next) {
console.log("A start");
typeof next === "function" && next();
console.log("A end");
}
function B(next) {
console.log("B start");
typeof next === "function" && next();
console.log("B end");
}
function C(next) {
console.log("C start");
typeof next === "function" && next();
console.log("C end");
}
function D() {
console.log("D start");
console.log("D end");
}
A(B.bind(null, C.bind(null, D)));
运行结果:
A start
B start
C start
D start
D end
C end
B end
A end
compose函数模拟
koa是通过koa-compose库进行中间件调用的,我们可以通过写一个简版compose函数模拟下
方式1:Array.prototype.reduceRight
const mws = [A, B, C, D];
function compose(allMW) {
return allMW.reduceRight((pre, cur) => {
return cur.bind(null, pre);
});
}
let mwFn = compose(mws);
mwFn();
方式2:柯里化方式(递归)
const mws = [A, B, C, D];
function compose(allMW) {
function dispatch(i) {
let middleware = allMW[i];
if (!middleware) return;
return middleware.bind(null, dispatch(i + 1));
}
return dispatch(0);
}
let mwFn = compose(mws);
mwFn();
三、简版koa
class Koa {
constructor() {
this.middlewareList = [];
this.context = {
request: null,
response: null,
};
}
use(middleware) {
this.middlewareList.push(middleware);
}
compose(middlewareList) {
return function (ctx) {
function dispatch(index) {
const middleware = middlewareList[index];
if (!middleware) return;
return middleware(ctx, dispatch.bind(null, index + 1));
}
return dispatch(0);
};
}
}
测试代码:
const app = new Koa();
app.use((ctx, next) => {
console.log("A start");
next();
console.log("A end");
});
app.use((ctx, next) => {
console.log("B start");
next();
console.log("B end");
});
app.use((ctx, next) => {
console.log("C start");
next();
console.log("C end");
});
app.use((ctx, next) => {
console.log("D start");
next();
console.log("D end");
});
const run = app.compose(app.middlewareList);
run();
运行结果:
A start
B start
C start
D start
D end
C end
B end
A end
koa-compose源码:入口
参考:
Last updated