Koa 洋葱模型(Onion Model)的原理与实现
请详细解释 Koa 中间件的洋葱模型(Onion Model)执行流程,对比 Express 的线性中间件模型,并说明 Koa 如何通过 async/await 实现嵌套调用。
回答
苦行僧
洋葱模型图示:
请求 → M1 前半 → M2 前半 → M3 前半 → 路由处理 → M3 后半 → M2 后半 → M1 后半 → 响应
核心原理:
- Koa 中间件是 async 函数,通过
await next()实现嵌套 next()返回 Promise,执行后续中间件,等 Promise resolve 后继续执行当前中间件后续代码- 内部使用
koa-compose包,将中间件数组组合成嵌套函数调用
compose 实现:
function compose(middleware) {
return function (context, next) {
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, dispatch.bind(null, i + 1)));
} catch (err) {
return Promise.reject(err);
}
}
};
}
Express vs Koa: | 特性 | Express | Koa | |------|---------|-----| | 模型 | 线性(请求→响应) | 洋葱(请求→响应→回程) | | 异步 | 回调,需第三方库 | async/await 原生 | | 上下文 | req/res 分离 | 统一 ctx 对象 | | 错误处理 | 4参数中间件 | try/catch + ctx.onerror | | 内置 | 路由、静态文件 | 极简核心 |