资讯专栏INFORMATION COLUMN

Koa 系列 —— Koa 中间件机制解析

blastz / 2174人阅读

摘要:中异步处理在中使用的是,在中使用的是,我们本次采用来处理异步。函数参数为的数组,数组成员是通过方法添加的中间件。小结从最开始的编写中间件,到现在阅读函数源码,中间件机制并不复杂,了解之后,我们可以运用编写更合适的中间件,构建自己的应用。

上一篇讲了如何编写属于自己的 Koa 中间件,本篇将根据原理实现一个简单的中间件处理函数,并对 Koa 中间件处理函数 compose 函数进行源码解析。

1. compose 函数简单实现

Koa 中间件采取的是中间件洋葱模型,具体原理可见如何编写属于自己的 Koa 中间件。本质就是将中间件嵌套执行:

function middleware0(){
  console.log("middleware0")
}
function middleware1(){
  console.log("middleware1")
}
// 将两个中间件嵌套执行
middleware0(middleware1())

当然实际上更复杂,还要考虑中间件的异步执行和中间件如何进行嵌套。Koa 中异步处理在 Koa1 中使用的是 generator + co.js,在 Koa2 中使用的是 async/await,我们本次采用 async/await 来处理异步。中间件的嵌套可以通过将中间件当参数传递来实现嵌套。据此我们对上面的代码进行进一步加工:

ps:Node7.6+ 支持 async/await
async function middleware0(next){
  console.log("middleware0")
  await next()
}
async function middleware1(next){
  console.log("middleware1")
}
// 将两个中间件嵌套执行
middleware0(middleware1)

Koa 中通过 compose 函数对中间件的进行处理。compose 函数参数为 middleware 的数组, middleware 数组成员是通过 use 方法添加的中间件。下面写个简单的 compose 函数,来实现多个中间件的处理:

async function middleware0(next){
  console.log("middleware0")
  await next()
  console.log("middleware0 end")
}
async function middleware1(next){
  console.log("middleware1")
  await next()
  console.log("middleware1 end")
}
async function middleware2(next){
  console.log("middleware2")
  await next()
  console.log("middleware2 end")
}

/**
 * @param {Array} 中间件数组
 */
function compose (middleware) {
  // 从第一个中间件开始执行
  return dispatch(0) 
  function dispatch(i){
    // 获取第 i 个中间件
    fn = middleware[i]
    // 获取不到中间件,则直接返回结束
    if(!fn) return
    // 执行第 i 个中间件,并传入第 i + 1 个中间件
    return fn(() => dispatch(i + 1))
  }
}
// 执行
compose([middleware0, middleware1, middleware2])
2. 源码解析

我们已经简单实现了一个 compose 函数,现在来看下 Koa 中源码的实现。Koa 中的 compose 函数已经提取到 koa-compose 包中,其中的核心代码如下:

/**
 * @param {Array} 中间件数组
 * @return {Function}
 */
function compose (middleware) {
  // 判断是否为数组,不是则抛出异常
  if (!Array.isArray(middleware)) throw new TypeError("Middleware stack must be an array!")
  // 判断 middleware 数组中的中间件是否为函数,不是函数抛出异常
  for (const fn of middleware) {
    if (typeof fn !== "function") throw new TypeError("Middleware must be composed of functions!")
  }
  /**
   * 此处先不执行中间件,直接返回函数
   * 统一在外面进行异常判断,再开始执行中间件
   */
  return function (context, next) {
    let index = -1
    // 从第一个中间件开始执行
    return dispatch(0)
    function dispatch (i) {
      // 同一个中间件多次调用 next 抛出异常
      if (i <= index) return Promise.reject(new Error("next() called multiple times"))
      index = i
      // 获取第 i 个中间件
      let fn = middleware[i]
      /**
       * 中间件执行结束,检查是否有传入 next 回调函数
       * 此 next 并非中间件执行的 next 参数
       */
      if (i === middleware.length) fn = next
      /**
       * 所有的返回都是Promise对象
       * Promise对象可以保证中间件和返回请求对象之间的执行顺序
       */
      if (!fn) return Promise.resolve()
      try {
        // 执行第 i 个中间件,并传入第 i + 1 个中间件
        return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
      } catch (err) {
        return Promise.reject(err)
      }
    }
  }
}

通过解析可以发现,源码相对于我们的实现更加健全:

更完善的异常处理

在执行前统一对传入参数进行检查

多次执行 next 函数抛出异常处理等

最终返回结果 Promise 化,保证中间件和整个处理函数在 Koa 中的执行顺序,具体可参考下面 Koa 源码片段:

/**
 * application.js
 * fnMiddleware(ctx) 就是 compose 函数返回的函数,默认不传入 next 参数
 * Promise 保证中间件,handleResponse 执行顺序。
 */
fnMiddleware(ctx).then(handleResponse).catch(onerror)
3. 小结

从最开始的编写 Koa 中间件,到现在阅读 compose 函数源码,Koa 中间件机制并不复杂,了解之后,我们可以运用、编写更合适的中间件,构建自己的 Koa 应用。

本文首发于公众号,更多内容欢迎关注我的公众号: 阿夸漫谈

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/101208.html

相关文章

  • Express与Koa间件机制分析(一)

    摘要:目前使用人数众多。通过利用函数,帮你丢弃回调函数,并有力地增强错误处理。这个系列的博客主要讲解和的中间件机制,本篇将主要讲解的中间件机制。其中间件机制的核心为内部方法的实现。 提到 Node.js 开发,不得不提目前炙手可热的2大框架 Express 和 Koa。 Express 是一个保持最小规模的灵活的 Node.js Web 应用程序开发框架,为 Web 和移动应用程序提供一组...

    zilu 评论0 收藏0
  • KOA2框架原理解析和实现

    摘要:实现的四大模块上文简述了源码的大体框架结构,接下来我们来实现一个的框架,笔者认为理解和实现一个框架需要实现四个大模块,分别是封装创建类构造函数构造对象中间件机制和剥洋葱模型的实现错误捕获和错误处理下面我们就逐一分析和实现。 什么是koa框架?        koa是一个基于node实现的一个新的web框架,它是由express框架的原班人马打造的。它的特点是优雅、简洁、表达力强、自由度...

    tracymac7 评论0 收藏0
  • KOA2框架原理解析和实现

    摘要:实现的四大模块上文简述了源码的大体框架结构,接下来我们来实现一个的框架,笔者认为理解和实现一个框架需要实现四个大模块,分别是封装创建类构造函数构造对象中间件机制和剥洋葱模型的实现错误捕获和错误处理下面我们就逐一分析和实现。 什么是koa框架?        koa是一个基于node实现的一个新的web框架,它是由express框架的原班人马打造的。它的特点是优雅、简洁、表达力强、自由度...

    liangzai_cool 评论0 收藏0
  • express分析和对比

    摘要:前言目前最新版本是所以本文分析也基于这个版本。源码分析直接切入主题由于目前是一个独立的路由和中间件框架。所以分析的方向也以这两个为主。源码去年的时候有分析过现在对比分析思考下。 前言 目前express最新版本是4.16.2,所以本文分析也基于这个版本。目前从npm仓库上来看express使用量挺高的,express月下载量约为koa的40倍。所以目前研究下express还是有一定意义...

    mmy123456 评论0 收藏0

发表评论

0条评论

blastz

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<