首先平时我们写middle ware都是像下面这样对不对?
async function fn1(next) {
console.log('fn1')
await next()
console.log('end fn1')
}
async function fn2(next) {
console.log('fn2')
await next()
console.log('end fn2')
}
async function fn3(next) {
console.log('fn3')
console.log('end fn3')
}
next方法是koa框架给我们的工具,那如果没有这个next我们怎么才能一层层调用下一个方法呢?我首先想到的就是 await/async,那就去掉next方法并自己动手改造一下!代码如下:
async function fn1(nextMiddleWarePointer) {
console.log('fn1')
if(nextMiddleWarePointer)
{
await nextMiddleWarePointer();
}
console.log('end fn1')
}
async function fn2(nextMiddleWarePointer) {
console.log('fn2')
if(nextMiddleWarePointer)
{
await nextMiddleWarePointer();
}
console.log('end fn2')
}
async function fn3(nextMiddleWarePointer) {
console.log('fn3')
if(nextMiddleWarePointer)
{
await nextMiddleWarePointer();
}
console.log('end fn3')
}
fn1(function(){
return fn2(function(){
return fn3()
})
} )
这个代码很容易理解,一个个中间件就像被一条链子穿起来一样,为了可以让当前的中间件可以调用下一个中间件我至少得把下一个中间件的引用传给它,就比如我想让fn2调fn3,我就得把fn3的引用当做参数传给fn2,上面代码中nextMiddleWarePointer就是下一个中间件的引用。最后在调用这个中间件链的时候,写法必然是一层套一层的,并且因为我们是把函数当做引用传进去供其调用,所以要在fn外面套一层函数,避免被直接调用。
下面开始优化上面代码,既然代码中出现了层层嵌套的写法那就必然可以替换成递归!下面就把它改造成递归。代码如下:
function compose(middleWareArray) {
return function () {
dispatch(0);
function dispatch(nextIndex) {
const fn = middleWareArray[nextIndex];
if (fn) {
return new Promise((resolve) => {
resolve(fn(function () {return dispatch(nextIndex + 1) }));
})
}
else {
return function () { };
}
}
}
}
async function fn1(nextMiddleWarePointer) {
console.log('fn1')
await nextMiddleWarePointer();
console.log('end fn1')
}
async function fn2(nextMiddleWarePointer) {
console.log('fn2')
await nextMiddleWarePointer();
console.log('end fn2')
}
async function fn3(nextMiddleWarePointer) {
console.log('fn3')
await nextMiddleWarePointer();
console.log('end fn3')
}
middleWareArray = [fn1, fn2, fn3];
const startFn = compose(middleWareArray);
startFn();
最后把compose函数再改造一下,如下:
function compose(middleWareArray) {
return function () {
dispatch(0);
function dispatch(nextIndex) {
const fn = middleWareArray[nextIndex];
if (fn) {
return Promise.resolve(fn(function () {return dispatch(nextIndex + 1) }));
}
else {
return Promise.resolve();
}
}
}
}
这个代码其实有不少值得细细玩味的地方,大家自行研究吧!