天天看点

koa中间件[email protected]中间价源码分析

@koa中间件 源码分析

[email protected]中间价源码分析

不废话直接

上代码

'use strict'

/**
 * Expose compositor.
 */

module.exports = compose

/**
 * Compose `middleware` returning
 * a fully valid middleware comprised
 * of all those which are passed.
 *
 * @param {Array} middleware
 * @return {Function}
 * @api public
 */

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!')
  }

  /**
	* context 是传入的上下文数据 在中间件被执行时都可以访问到
	* next 是中间都被执行完后 被执行的回调函数
   */
  return function (context, next) {
    /**
    * 作为开始和结束的开关
    */
    let index = -1

    function dispatch(i) {
      /**
       * 如果 传入的 i 值 小于或等于 index 直接退出
       */
      if (i <= index) return Promise.reject(new Error('next() called multiple times'))

      /**
       * 给index赋值当前的i的值
       */
      index = i
      /**
       * 创建fn变量为传入中间件数组的第i个
       */
      let fn = middleware[i]
      /**
       * 如果 i 和 中间件数组的长度相等 说明是中间件函数已经执行完毕
       * 给fn变量重新赋值为next
       */
      if (i === middleware.length) fn = next
      /**
       * 如果fn是空的时候 退出这个中间件的执行
       */
      if (!fn) return Promise.resolve()
      try {
        /**
         * 返回一个Promise成功对象
         * fn 为 中间件方法
         * 值为 中间件方法执行 
         * 传入fn函数执行时传入的参数context
         * dispatch.bind(null, i + 1)) === next 方法为 调用下一个中间件执行
         */
        return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
      } catch (err) {
        /**
         * 捕获到错误直接退出中间件执行
         */
        return Promise.reject(err)
      }
    }
    return dispatch(0)
  }
}

const middleware = [
  function (context, next) {
    console.log(context, 'context')
    console.log(1, 'middleware')
    next()
  },
  function (context, next) {
    console.log(context, 'context')
    console.log(2, 'middleware')
    next()
  },
  function (context, next) {
    console.log(context, 'context')
    console.log(3, 'middleware')
    next()
  },
]

/**
 * 第一个参数为中间件数组
 * 第二参数为context
 */
compose(middleware)('我是帅哥', () => {
  console.log('结束了')
})
           

继续阅读