koa-connect源碼解析


文中提到的koa均為koa2
提到nodejs, 想必大家都知道express和koa.
express: 大
koa: 小
比較的的是功能, 社區, 中間件,相關資源等

這里我就專門說說中間件吧, 很多人可能說express插件豐富啊. 其實除了中間件, 其余什么的和express koa本身並沒有多大關系, 不都是基於nodejs http(https)的封裝嘛.

express中間件是非常的豐富, 但是提個醒, express的中間件是可以跑在koa下面的.到這里就要提到 koa-connect.

那么,我們就來簡單看看這個koa-connect是怎么實現的.
其源碼一共才38行, 一半多注釋, 3個方法.

  • koaConnect: 對外公布的方法, 對express的中間件的參數進行分析,分別調用noCallbackHandler和withCallbackHandler
  • noCallbackHandler : 處理無回調的express的中間件
  • withCallbackHandler : 處理有回調的express的中間件
    這里的回調就是有無next方法, next方法就是進入下一個中間件
/**
 * If the middleware function does declare receiving the `next` callback
 * assume that it's synchronous and invoke `next` ourselves
 */
function noCallbackHandler(ctx, connectMiddleware, next) {
  connectMiddleware(ctx.req, ctx.res)
  return next()
}

/**
 * The middleware function does include the `next` callback so only resolve
 * the Promise when it's called. If it's never called, the middleware stack
 * completion will stall
 */
function withCallbackHandler(ctx, connectMiddleware, next) {
  return new Promise((resolve, reject) => {
    connectMiddleware(ctx.req, ctx.res, err => {
      if (err) reject(err)
      else resolve(next())
    })
  })
}

/**
 * Returns a Koa middleware function that varies its async logic based on if the
 * given middleware function declares at least 3 parameters, i.e. includes
 * the `next` callback function
 */
function koaConnect(connectMiddleware) {
  const handler = connectMiddleware.length < 3
    ? noCallbackHandler
    : withCallbackHandler
  return function koaConnect(ctx, next) {
    return handler(ctx, connectMiddleware, next)
  }
}

module.exports = koaConnect

koaConnect方法

function koaConnect(connectMiddleware) {
  const handler = connectMiddleware.length < 3
    ? noCallbackHandler
    : withCallbackHandler
  return function koaConnect(ctx, next) {
    return handler(ctx, connectMiddleware, next)
  }
}

kaoConnect返回的是一個koa版本的中間件.

connectMiddleware.length是express中間件參數的長度, 如果你這個中間件使用了arguments進行參數解析或者使用了rest參數, 那么這個length本身就准確了.

通過express中間件參數的長度分別調用有回調和無回調的方法.

noCallbackHandler方法

function noCallbackHandler(ctx, connectMiddleware, next) {
  connectMiddleware(ctx.req, ctx.res)
  return next()
}

直接調用express方法, ctx.req 和 ctx.res作為參數傳入.
ctx.req: Node 的 request 對象.
ctx.res: Node 的 Reponse 對象.

這說明express的中間的req 和 res 和koa中間件的ctx.req 和res就是一個玩意.

因為express中間件沒有調用next, 所以被調用完畢, 直接調用koa中間件的next

withCallbackHandler方法

function withCallbackHandler(ctx, connectMiddleware, next) {
  return new Promise((resolve, reject) => {
    connectMiddleware(ctx.req, ctx.res, err => {
      if (err) reject(err)
      else resolve(next())
    })
  })
}

返回一個Promise, 因為koa中有 await next()的形式調用, 這就很好的滿足了需求.
express中間里面假如有第三個參數next,調用表示進入下一個中間件.
express中間件next調用的時候可以傳入Error,
可以參考express error handling

app.get("/", function (req, res, next) {
  fs.readFile("/file-does-not-exist", function (err, data) {
    if (err) {
      next(err); // Pass errors to Express.
    }
    else {
      res.send(data);
    }
  });
});

回到我們的withCallbackHandler方法
這里express的中間件的next方法即為

err => {
      if (err) reject(err)
      else resolve(next())
    }

當有錯誤的時候,reject
當沒有錯誤的時候, 調用koa中間件的next, 繼續下面的執行.

koa-connect就分析完畢了, 核心就兩點

  1. 通過express中間件的參數長度來區分處理
  2. 改造express中間件的next方法


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM