See the Pen Koa.js compose by Willard (@ifyour) on CodePen.
// Koa.js 核心代码 compose
// 决定了 Koa.js 中间件的调用顺序,也就是洋葱模型
function compose(middleware) {
return function(context, next) {
// 最后调用的 middleware 索引
let index = -1;
return dispatch(0);
function dispatch(i) {
if (i <= index)
return Promise.reject(new Error("next() called multiple times"));
index = i;
let fn = middleware[i];
if (i === middleware.length) fn = next;
if (!fn) return Promise.resolve(); // 结束递归条件
try {
return Promise.resolve(
fn(context, function next() {
return dispatch(i + 1); // 递归调用自身
})
);
} catch (err) {
return Promise.reject(err);
}
}
};
}
async function a (ctx, next) {
console.log(1);
const hello = await Promise.resolve('Hello, node.js');
console.log(hello);
await next();
console.log('a end');
}
async function b (ctx, next) {
console.log(2);
const hello = await Promise.resolve('Hello, node.js');
console.log(hello);
await next();
console.log('b end');
}
//
// Demo:测试中间件调用
//
const myCtx = {};
compose([a, b])(myCtx);
执行结果:
1
"Hello, node.js"
2
"Hello, node.js"
"b end"
"a end"