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
首先逸贾,關(guān)于 洋蔥模型 自上而下-》自下而上 回溯機制并不是 koa 自己的特性次询,而是 async/await 自己執(zhí)行順序的特定峰鄙,就是 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 執(zhí)行時栖袋,會先去執(zhí)行后面的 異步函數(shù)叹卷,等待后面 異步函數(shù)有了結(jié)果舒岸,才會繼續(xù)執(zhí)行 await 后面的代碼绅作,自己本身就具有 “回溯機制”
koa 只是做了一件事,就是 創(chuàng)建了 next 函數(shù)蛾派,這個函數(shù)的作用就是調(diào)用下一個中間件
下一個中間件同樣需要 next 參數(shù)俄认,所以我們需要依照中間件列表倒序構(gòu)建 next 函數(shù),先構(gòu)建最后一個中間件需要的 next 函數(shù)洪乍,然后再構(gòu)建倒數(shù)第二個中間件需要的 next 函數(shù)...以此類推
最后呢眯杏,所有中間件就構(gòu)成了一條鏈。我們調(diào)用鏈開頭的 next 函數(shù)壳澳,每個鏈條節(jié)點中又調(diào)用
await next()
調(diào)用下一個中間件岂贩,最終所有中間件都得到了執(zhí)行。
構(gòu)建 next 函數(shù)我們可以封裝一下巷波,是這個樣子:
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 參數(shù),我們可以創(chuàng)造一個空的 async 函數(shù)
const next = async () {}
//...
m3(next)