函数复合是实现洋葱模型最直接的方式,通过高阶函数嵌套与从右到左的包裹顺序(如a(b(c(handler)))),使外层中间件最先调用、最后结束,天然形成“前置→next→后置”的两段式执行流。

函数复合是实现洋葱模型最直接、最本质的方式——它不依赖框架,只靠高阶函数的嵌套与顺序调用,就能自然还原“外→内→外”的执行路径。
核心原理:从 compose 到洋葱结构
洋葱模型的关键不是“有多少层”,而是“每层能控制进入和退出时机”。函数复合通过 从右到左依次包裹 的方式,让最外层中间件最先被调用、最后结束,形成天然的两段式执行(前置 → next → 后置):
- compose([a, b, c])(handler) 等价于 a(b(c(handler)))
- c 最靠近业务 handler,最先执行其前置逻辑,也最先执行其后置逻辑
- a 在最外层,前置逻辑最早运行,后置逻辑最晚运行,正好包住整个流程
中间件函数签名要统一
所有中间件必须遵循同一契约,才能被 compose 安全组合。推荐签名是:
(ctx, next) => { /* 前置逻辑 */; await next(); /* 后置逻辑 */ }
前端设计与 UI/UX 全方位优化专家。覆盖视觉层次、排版系统、色彩理论、响应式布局、交互体验、动画动效、无障碍访问、性能优化八大维度,帮助开发者将普通页面升级为高品质产品级界面。前端设计与 UI/UX 全方位优化专家。覆盖视觉层次、排版系统、色彩理论、响应式布局、交互体验、动画动效、无障碍访问、性能优化八大维度,帮助开发者将普通页面升级为高品质产品级界面。
- ctx 是贯穿全程的上下文对象,用于透传数据、修改响应、中断流程
- next 是由 compose 自动注入的“下一个中间件返回的函数”,调用它即进入内层
- 不调用 next 就等于截断流程,适合鉴权失败、日志拦截等场景
手写一个轻量 compose 支持异步
不需要引入库,几行代码就能支撑真实项目:
const compose = (middlewares) => (ctx) => {
let index = -1;
const dispatch = (i) => {
if (i index = i;
const fn = middlewares[i];
if (!fn) return Promise.resolve();
return Promise.resolve(fn(ctx, () => dispatch(i + 1)));
};
return dispatch(0);
};
- 用递归 dispatch 控制调用序号,避免重复调用 next 导致混乱
- 每个中间件拿到的 next 都是 dispatch(i + 1),天然形成链式闭环
- Promises 包裹确保 await next() 正确等待内层完成,再执行后置逻辑
典型使用模式:分层职责清晰
按洋葱层级组织中间件,越外层越通用,越内层越具体:
- 外层:请求日志、耗时统计、CORS 处理
- 中层:身份校验(JWT 解析)、权限检查(RBAC 判断)、请求体解析
- 内层:业务路由分发、具体控制器执行、错误统一兜底
这样任意一层都能在 request 进入时做预处理,在 response 返回前做增强,比如日志中间件既记录开始时间,又在 next 结束后补上响应码和耗时。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










