async function m1(next) {
console.log('m1')
await next()
console.log('e')
}
async function m2(next) {
console.log('m2')
await next()
console.log('d')
}
async function m3(next) {
console.log('m3')
await next()
}
const next3 = async () => {
m3()
}
const next2 = async () => {
m2(next3)
}
const next1 = async () => {
m1(next2)
}
next1()
// 输出:
// m1
// m2
// m3
// d
// e
首先,关于 洋葱模型 自上而下-》自下而上 回溯机制并不是 koa 自己的特性,而是 async/await 自己执行顺序的特定,就是 async/await 自带这个特性
可以写个 demo 验证一下:
async function a1() {
console.log('a1')
await a2()
console.log('a3')
}
async function a2() {
console.log('a2')
}
a1()
// 输出
// a1
// a2
// a3
也就是, await 执行时,会先去执行后面的 异步函数,等待后面 异步函数有了结果,才会继续执行 await 后面的代码,自己本身就具有 “回溯机制”
koa 只是做了一件事,就是 创建了 next 函数,这个函数的作用就是调用下一个中间件
下一个中间件同样需要 next 参数,所以我们需要依照中间件列表倒序构建 next 函数,先构建最后一个中间件需要的 next 函数,然后再构建倒数第二个中间件需要的 next 函数...以此类推
最后呢,所有中间件就构成了一条链。我们调用链开头的 next 函数,每个链条节点中又调用
await next()
调用下一个中间件,最终所有中间件都得到了执行。
构建 next 函数我们可以封装一下,是这个样子:
function createNext (middleware, oldNext) {
return async () => {
await middleware(ctx, oldNext)
}
}
const len = this.middlewares.length;
let next = async () => {
return Promise.resolve()
}
for (let i = len - 1; i >= 0; i--) {
let currentMiddleware = this.middlewares[i]
next = createNext(currentMiddleware, next)
}
await next()
同时,为了使最后一个中间件也有 next 参数,我们可以创造一个空的 async 函数
const next = async () {}
//...
m3(next)