美文网首页
koa1.x中间件与co的实现

koa1.x中间件与co的实现

作者: 任无名F | 来源:发表于2017-11-09 10:37 被阅读0次

单纯的co实现

co的初衷就是自执行generator,并且提供对Promise对象的支持

function co(generator, data) {
  const result = generator.next(data) // 此处执行generator的next,获取结果
  if(result.done) { // 若generator已执行到末尾,则结束
    return
  } else { // 否则,针对其value进行处理
    const value = result.value
    if(value instanceof Promise) { // 若value为Promise对象
      value.then(data => { // 待此Promise对象resolve后,再继续执行下面的next
        co(generator, data) // 继续执行co,其本质是执行generator的next
      })
    } else {
      co(generator, value) // value为普通值,则直接继续执行co
    }
  }
}

koa1.x中间件的实现

koa1的中间件是基于generator实现的,所以其中也包括变种的co,其著名的洋葱模型如下:


洋葱模型1
洋葱模型2

实现代码如下:

let index = 0, // 中间件数组的序号,用于标记执行进度
    middleware = [], // 中间件数组,剥洋葱自内而外的过程会遍历它,use方法将会填充它
    glist = [], // 中间件在yield next之后的generator保存在这个数组中,等待以后执行,剥洋葱自外而内的阶段会遍历它
    NEXT = {}, // NEXT标识,对象类型,以参数形式传给中间件,当中间件yield next的时候,就表示要执行下一个中间件
    ctx // 此变量代表koa1.x的上下文

function use(fn) { // use的本质是将中间件generator推进middleware数组,参数fn为generator函数
  middleware.push(fn);
}

function run() { // 执行所有中间件的方法
  next(); // 递归执行next方法
  function next() {
    const mid = middleware[index] // 从0开始,依次取出中间件

    if(mid) { // 若存在此中间件
      const gen = mid.bind(ctx, NEXT) // 为中间件方法绑定ctx上下文,并传入NEXT标识
      co(gen) // co执行此中间件生成的generator
    } else { // 若不存在此中间件,则说明由内而外的阶段已经结束,下面进入剥洋葱由外而内的阶段
      index-- // index自减
      const gen = glist[index] // 找到紧邻的内层generator,执行
      co(gen)
    }
  }

  function co(gen, data) {
    const result = gen.next(data); // 执行next,且如果有data,传入data

    if(result.done) { // 此generator已执行完,此情况一定为剥洋葱由外而内的阶段
      index-- // 由外而内,故index自减
      const gen = glist[index] // 找到紧邻的内层generator,执行
      co(gen)
      return
    }
    const value = result.value // 判断generator的value
    if(value instanceof Promise) { // 若为Promise对象
      value.then(data => { // 则在此Promise完成resolve后,再继续执行generator
        co(gen, data)
      })
    } else if(value === NEXT) { // 此处比较NEXT标识,若相等则说明调用了yield next,则进行剥洋葱由内而外的下一阶段
      glist.push(gen) // 保存未执行完的generator对象,等待未来由外而内阶段时再来执行
      index++ // index自增
      next() // 继续进行剥洋葱由内而外
    } else { // 此情况为generator的普通yield,则继续执行generator
      co(gen, value)
    }
  }
}
          

相关文章

网友评论

      本文标题:koa1.x中间件与co的实现

      本文链接:https://www.haomeiwen.com/subject/ypqpmxtx.html