实现
2023年08月03日
一、认识
express
中间件用于处理 http
的请求和响应。采用 尾递归 的方式, 中间件一个接一个的顺序执行, 习惯于将 response
响应写在最后一个中间件中。
二、实现
function compose(req,res,middleware) {
let index = 0;
function next(error) {
if (index >= middleware.length) {
console.log("error", error);
return;
}
while (index < middleware.length) {
const fn = middleware[index++];
fn(req, res, next);
}
}
next();
}
next
不断取出 middleware
中的中间件进行调用, 同时把 next
本身传递给 中间件 作为第三个参数。每个中间件约定的固定形式为 (req, res, next) => {}
, 这样每个**中间件*函数中只要调用 next 方法即可传递调用下一个中间件。
express
的中间件是一个 尾递归调用, 之所以说是尾递归是因为递归函数的最后一条语句是调用函数本身,所以每一个中间件的最后一条语句需要是**next()
才能形成尾递归**,否则就是普通递归,尾递归相对于普通”递归“的好处在于节省内存空间,不会形成深度嵌套的函数调用栈。
三、调试
let fn1 = async function (context, next) {
console.log("fn1 之前");
await next();
console.log("fn1 之后");
};
let fn2 = async function (context, next) {
console.log("fn2 之前");
await next();
console.log("fn2 之后");
};
let fn3 = async function (context, next) {
console.log("fn3 之前");
await next(); // 最后一个中间件的 next 可有可无
console.log("fn3 之后");
};
let middleware = [fn1, fn2, fn3];
compose(middleware)({});
四、问题
4.1 express 可以用 async function 作为中间件用于异步处理吗?
答: express
的中间件的执行是同步的 while
循环, 当中间件同时包含普通普通函数和 async
函数时, 执行顺序会打乱。有可能执行到 await
后再次执行 next
索引会超出的情况。