koa源碼解析

用法回顧

const Koa = require('koa');
const app = new Koa();

app.use(async (ctx, next) => {
  fn1();
  await next();
  fn2();
});

app.use(async (ctx, next) => {
  fn3();
  await next();
  fn4()
});

app.use(async (ctx, next) => {
  fn5();
  await next();
  fn6()
});

app.listen(3000);

執行順序 fn1 -> fn3 -> fn5 -> fn6 -> fn4 -> fn2
每當執行next時,執行下一個中間件,執行到最後一箇中間件後開始往回執行javascript

源碼解析

源碼執行步驟

  1. 使用use方法即將middleware push 進koa中的this.middleware數組中
  2. listen方法調用node的http.createServer和server.listen方法來建立服務,createServer的回掉執行下面的操做
  3. 回掉首先執行compose(this.middleware)方法將middleware組合成一個promise對象來執行,這個promise對象便可完成中間件級聯的操做
  4. 將回掉傳出的值req和res用於建立一個context對象,裏面包含了request對象和response對象,這些對象提供了許多後臺開發須要的參數和方法
  5. 執行中間件
  6. 獲得結果給respond方法格式化數據
  7. 或者捕獲異常給onerror方法處理異常

compose

koa源碼最重要的部分,如何實現中間件級聯,如下是compose方法的源碼(爲方便觀看,部分進行了ES6處理)java

function compose (middleware) {
  if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!')
  for (const fn of middleware) {
    if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!')
  }

  return function (context, next) {
    // last called middleware #
    let index = -1
    return dispatch(0)
    function dispatch (i) {
      if (i <= index) return Promise.reject(new Error('next() called multiple times'))
      index = i
      let fn = middleware[i]
      if (i === middleware.length) fn = next // next = undefined
      if (!fn) return Promise.resolve() // 當運行到最後一個middleware時結束
      try {
        return Promise.resolve(
          fn(context, next = () => dispatch(i + 1))
        )
      } catch (err) {
        return Promise.reject(err)
      }
    }
  }
}
  1. compose方法使用遞歸的方式遍歷每個middleware
  2. 遍歷時將下一個middleware看成next傳遞給當前的middleware

更多文章 yjy5264.github.io

相關文章
相關標籤/搜索