侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1823 篇文章
  • 累计收到 0 条评论

实现一个中间件执行流程的洋葱模型

2025-12-7 / 0 评论 / 6 阅读

题目

实现一个中间件执行流程的洋葱模型

信息

  • 类型:问答
  • 难度:⭐⭐

考点

中间件原理, 洋葱模型, 异步流程控制

快速回答

实现洋葱模型的核心要点:

  • 使用compose函数组合中间件
  • 每个中间件接收contextnext参数
  • 通过await next()控制执行流程
  • 递归执行形成先进后出的调用栈
## 解析

原理说明

洋葱模型指请求从外到内穿透中间件层,响应从内到外返回的流程。核心是compose函数:

  1. 中间件数组被组合成嵌套函数
  2. 每个中间件执行时遇到await next()暂停
  3. 控制权转移到下一个中间件
  4. 当最后一个中间件完成后,逐层回溯执行剩余代码

执行顺序:
Middleware1 start → Middleware2 start → Middleware3 start → 业务逻辑 → Middleware3 end → Middleware2 end → Middleware1 end

代码实现

function compose(middlewares) {
  return function (context) {
    return dispatch(0);

    function dispatch(i) {
      const fn = middlewares[i];
      if (!fn) return Promise.resolve();

      try {
        // 关键:next 是下一个中间件的封装
        return fn(context, () => dispatch(i + 1));
      } catch (err) {
        return Promise.reject(err);
      }
    }
  };
}

// 使用示例
const app = {
  middlewares: [],
  use(fn) {
    this.middlewares.push(fn);
  },
  run(ctx) {
    return compose(this.middlewares)(ctx);
  }
};

// 添加中间件
app.use(async (ctx, next) => {
  console.log('Middleware 1 start');
  await next();  // 执行权移交
  console.log('Middleware 1 end');
});

app.use(async (ctx, next) => {
  console.log('Middleware 2 start');
  ctx.data = 'processed';
  await next();
  console.log('Middleware 2 end');
});

// 运行
app.run({}).then(() => console.log('Done'));
/* 输出:
Middleware 1 start
Middleware 2 start
Middleware 2 end
Middleware 1 end
Done
*/

最佳实践

  • 错误处理:在最外层添加错误捕获中间件
  • 性能优化:避免在中间件中进行阻塞操作
  • 上下文设计:使用独立context对象避免污染全局
  • 异步控制:始终返回Promise保证执行顺序

常见错误

错误类型后果解决方案
忘记调用await next()后续中间件不执行确保每个中间件正确调用next
未处理异步错误导致进程崩溃try/catch包裹中间件逻辑
修改共享状态未同步上下文数据不一致使用async/await保证执行顺序

扩展知识

  • Koa vs Express:Koa使用洋葱模型,Express是线性流水线
  • 性能影响:中间件层级不宜过深(建议≤10层)
  • 适用场景:身份验证、日志记录、请求超时处理等
  • 高级技巧:使用Promise.all实现并行中间件执行