题目
实现一个简单的中间件系统
信息
- 类型:问答
- 难度:⭐⭐
考点
中间件原理,洋葱模型,异步流程控制
快速回答
实现一个中间件系统的核心要点:
- 使用
use()方法注册中间件函数 - 通过
next()控制执行流程 - 采用洋葱模型(先进后出)的执行顺序
- 使用递归或Promise处理异步
1. 中间件核心原理
中间件本质是函数队列,通过next控制执行流。典型执行顺序:
// 洋葱模型执行顺序
→ Middleware1 前置
→ Middleware2 前置
→ 核心逻辑
← Middleware2 后置
← Middleware1 后置2. 代码实现示例
基础实现(同步):
class MiddlewareSystem {
constructor() {
this.middlewares = [];
}
use(fn) {
this.middlewares.push(fn);
}
run() {
const dispatch = (i) => {
if (i >= this.middlewares.length) return;
const middleware = this.middlewares[i];
return middleware({}, () => dispatch(i + 1));
};
dispatch(0);
}
}
// 使用示例
const app = new MiddlewareSystem();
app.use((ctx, next) => {
console.log('Middleware 1 start');
next();
console.log('Middleware 1 end');
});
app.run();支持异步(Promise):
class AsyncMiddlewareSystem {
constructor() {
this.middlewares = [];
}
use(fn) {
this.middlewares.push(fn);
}
run() {
const dispatch = (i) => {
if (i >= this.middlewares.length) return Promise.resolve();
const middleware = this.middlewares[i];
return Promise.resolve(middleware({}, () => dispatch(i + 1)));
};
return dispatch(0);
}
}3. 最佳实践
- 错误处理:添加catch捕获异常
app.use(async (ctx, next) => { try { await next(); } catch (err) { console.error(err); } }); - 上下文传递:通过
ctx对象共享数据 - 提前终止:不调用
next()可中断执行流
4. 常见错误
- 忘记调用next():导致后续中间件不执行
- 多次调用next():引发不可预测行为
- 异步未处理:未返回Promise导致执行顺序错乱
- 未处理错误:异步错误未捕获导致进程崩溃
5. 扩展知识
- Koa中间件原理:基于
koa-compose的递归Promise链 - Express与Koa区别:Express基于回调(非纯洋葱),Koa基于Promise
- 性能优化:使用
while循环替代递归减少调用栈深度 - 实际应用:路由、日志、鉴权、数据校验等场景