middleware 函数是一个具有 next 参数的函数,middleware 函数内会在某个地方调用 next 函数以执行下一个 middleware 函数,此 middleware 函数不会停止执行,而是在下一个 middleware 函数返回后继续执行剩余代码,例如:
function middleware1(next) {
console.log("1 start")
next()
console.log("1 end")
}
function middleware2(next) {
console.log("2 start")
next()
console.log("2 end")
}
function middleware3(next) {
console.log("3 start")
next()
console.log("3 end")
}
实现一个 compose 函数,它接受一个 middleware 函数数组 middlewares,并返回一个函数,返回的函数会从第一个 middleware 函数开始执行这些 middleware 函数。
例如:
compose([middleware1, middleware2, middleware3])()
将输出:
1 start
2 start
3 start
3 end
2 end
1 end
递归方式
function compose(middlewares) {
return function() {
function dispatch(i) {
if (i >= middlewares.length) return;
const middleware = middlewares[i];
middleware(() => dispatch(i + 1));
}
dispatch(0);
}
}
递归方式比较容易想到,但是如果 middlewares 数组非常长,递归调用可能会导致调用栈溢出,例如以如下方式调用时:
function createMiddleware(i) {
return function (next) {
console.log(i + " start");
next();
console.log(i + " end");
};
}
const middlewares = [];
for (let i = 1; i <= 4000; i++) {
middlewares.push(createMiddleware(i));
}
compose(middlewares)();
解决调用栈溢出问题
我不会。
如果用循环来执行不能使 next() 之后的代码在下一个中间件执行完毕后继续执行,而是会在下一个中间件执行前执行,即输出变成:
1 start
1 end
2 start
2 end
3 start
3 end
使用异步操作也是同样的问题。
可能可以的考虑的方法:生成器函数(可以暂停的函数),或者将 next() 前后的代码拆分成两个部分,但是实现起来不太可能。
所以这题有没有解?