koa2洋蔥中學習async

由於記性差因此記錄下來,看源碼更多的時候看一種思想,koa2使用了不少es6的語法,因此就以看源碼來學習語法吧。 看完koa的源碼,最核心的一塊就是洋蔥式調用。因此我就單獨吧這塊的代碼簡化下來,以便本身之後忽然想起來再看的時候不須要從新去捋思路了。node

  • 首先建立一個存儲函數的數組middleware
  • app.use將中間件存入middleware數組,數組準備好之後啓動服務
  • 啓動服務之後調用回調,將middleware數組裏中間件遞歸執行一次
  • 執行結束後返回Promise
  • 我就以這個順序把函數獨立出來,而且刪了一些原做者驗證的代碼和console代碼, 這裏假設每一個方法都是屬於app這個實例的,就不以app.來寫了。獨立出來

middleware是在實例上建立了一個空數組,

use(fn) {
    if (typeof fn !== 'function') throw new TypeError('middleware must be a function!');
    if (isGeneratorFunction(fn)) {

        fn = convert(fn);
        //轉換爲async 函數
    }
    this.middleware.push(fn);
    return this;
    //返回新實例
}

複製代碼

use方法就是將全部中間件放入middleware裏。

app.listen(3000, () => {

})


複製代碼

數組準備好之後啓動服務

listen(...args) {

    const server = http.createServer(this.callback());
    return server.listen(...args);
}

複製代碼

建立node服務器調用回調

callback() {
    const fn = compose(this.middleware);

    if (!this.listeners('error').length) this.on('error', this.onerror);

    const handleRequest = (req, res) => {
        const ctx = this.createContext(req, res);
        return this.handleRequest(ctx, fn);
    };

    return handleRequest;
}
複製代碼

callback在回調裏調用compose方法

function compose (middleware) {
   //middleware 回調數組
    return function (context, next) {
        // last called middleware #
        let index = -1;
        return dispatch(0)
    }
    //返回一個prm狀態
}
複製代碼

返回一個Promise對象 告訴遞歸調用完成的結果

function dispatch (i) {
    if (i <= index) return Promise.reject(new Error('next() called multiple times'))
    //判斷若是i小於index直接返回錯誤
    index = i;
    let fn = middleware[i]; //取出數組中對應下標函數
    if (i === middleware.length) fn = next;
   
    if (!fn) return Promise.resolve();
    
    try {
        return Promise.resolve(fn(context, function next () {
            return dispatch(i + 1)
            //遞歸調用
        }))
    } catch (err) {
        return Promise.reject(err)
    }
}
由於是async  因此當 await 接收到返回的Promise結果之後就會逐個執行下去 ,
也就是說當async函數被逐個執行完畢之後返回一個Promise對象,那麼就會從async函數最後一個await逐個向上返回調用,直到全部await執行完畢。
這就是洋蔥式調用
 async function(){
  await fun1(async function() {
    await fun2(async function() {
      await fun3(async function(){
        return Promise.resolve();
      });
    });
  });
};
上一級的await一直在等待下一級的返回結果,因此逐級向下執行,在等到執行了Promise.resolve();有了返回結果之後再逐級向上返回
//
複製代碼

遞歸調用的具體執行

handleRequest(ctx, fnMiddleware) {
   
    return fnMiddleware(ctx).then(handleResponse).catch(onerror);
    //fnMiddleware 就是遞歸執行完畢之後返回prm對象接收一個函數
}
//callback裏調永compose函數並將middleware傳遞過去

複製代碼

//最後一行其實就是返回的fn對象es6

總結

koa的思想其實就是運用了es7的新特性async函數的新特性,逐個等待異步的結果,一旦下層的返回結果就會逐個告訴轉達給上層,就造成了洋蔥式的調用,因此要讀懂源碼必須瞭解async函數,因此在讀碼的時候也同時學習複習了async函數,仍是很不錯的。若是不懂這個函數也許會在遞歸調用那塊搞暈,會不明白遞歸調用完了之後爲何會按順序返回結果。我以爲搞懂這個就算是搞懂koa2的核心思想了,其餘的都是一些封裝函數,能夠慢慢看數組

app.use(async (ctx, next) => {
  console.log(1)
  //典型語法await在等待
  await next();
  console.log(2)
});
app.use(async (ctx, next) => {
  console.log(3)
  //典型語法await在等待
  await next();
  console.log(5)
});
返回結果 是 1,3,5,2,
這就是洋蔥
這裏附上經典的圖吧

複製代碼

相關文章
相關標籤/搜索