Koa洋葱模型讲解 祛魅洋葱模型的本质就是递归constfn(index){if(index3)return;console.log(index,前);fn(index1);console.log(index,后);};fn(0);//输出://0 前//1 前//2 前//2 后//1 后//0 后异步的正常情况constsleep()newPromise((resolve)setTimeout(resolve,200));constfn1async(){console.log(111);awaitsleep();console.log(222);};constfn2async(){console.log(333);awaitsleep();console.log(444);};fn1();fn2();//输出//111//333//222//444解释执行fn1()时111会同步输出执行sleep()会同步生成一个定时器现在的promise为pending状态接着会同步执行fn2()输出333接着同样生成一个定时器。此时等fn1()中的promise状态改变之后会以微任务的形式执行222的输出444的输出同理。模拟实现KoaclassMyKoa{middlewares[];use(middleware){this.middlewares.push(middleware);returnthis;}compose(ctx){constdispatch(index){if(indexthis.middlewares.length){returnPromise.resolve();}constmiddlewarethis.middlewares[index];returnPromise.resolve(middleware(ctx,()dispatch(index1)));};returndispatch(0);}listen(){constctx{};this.compose(ctx).then((){console.log(done);});}}核心就一句话returnPromise.resolve(middleware(ctx,()dispatch(index1)));神奇之处constappnewMyKoa();app.use(async(ctx,next){console.log(111);awaitnext();console.log(222);});app.use(async(ctx,next){console.log(333);awaitnext();console.log(444);});app.listen();//输出//111//333//444//222按理说111、333输出之后应该输出222但却先输出了444再输出222。解释先明白一点递归其实是分为递和归两个动作111输出后执行的next其实是在递把执行权交给下一个中间件函数然后输出333接着执行333下面的next因为它是最后一个中间件了所以会执行到if (index this.middlewares.length) { return Promise.resolve(); }因为现在还是在递阶段任务栈中只在处理当前递到的这个函数。所以当333下面的next执行时它会等着这个promise的状态被resolve因为没有其它的任务栈了所以随即执行444当444执行后进入归阶段会回到111下面的next同理执行后面的代码。