CO & Generator

179 阅读2分钟

「这是我参与2022首次更文挑战的第20天,活动详情查看:2022首次更文挑战

Co 函数库

  • 作者:TJ Holowaychuk TJ 大神
  • 诞生日期:2013 年 6 月
  • 作用:自动执行 Generator 函数
  • 原理:
    • 自动执行器 Thunk 函数 + 自动执行器 Promise 对象 => Co 库
    • 参数:Generator 函数
    • return Promise 对象
    • yield Thunk 函数
    • yield Promise 函数

Generator 函数

  • 组成:
    • funciton* funcName()
    • { yield 表达式 }
  • 作用:使异步请求也能按照同步的方式顺序执行
  • yield 约等于 暂停键
    • 遍历器对象 Iterator 的 next() 方法首次调用,会从 generator 函数中的第一行代码开始,执行到 yield 后的表达式的位置
    • 执行 yield 后的程序后,需要等待 ⌛️ 遍历器对象 Iterator 的 next() 方法被调用,才会继续执行
    • yield 表达式会返回一个值
  • generator 函数生产的 Iterator 对象可以通过 for...of 来遍历

Thunk 函数

  • 多参数函数 => 单参数函数
  • 参数:回调函数
  • 柯里化
  • thunk 函数 + generator 函数
    • thunk 函数左 yield 的表达式
    • 每次执行 next 方法,都会执行一次 thunk 函数

Promise 函数

  • 三个状态 【 pending、fulfilled、rejected 】
    • pending 进行中
    • fulfilled 成功状态
    • rejected 失败状态
  • 两个参数 【 resolve()、reject() 】
    • resolve() 【 pending -> resolved 】 执行.then()
    • rejected() 【 pending -> rejected 】 执行.catch()
  • 作用:生成 Promise 实例 【 new Promise() 】
  • async / await 使异步请求也能按照同步的方式顺序执行
  • 模拟 co 库功能
    • 控制异步流程 【 依次执行 generator 中 yield 的表达式 (即 Promise 对象),并通过 resolve 或 reject 返回的结果 】

Co 函数库 & Generator 函数

  • yield 表达式 【 函数 + Promise 对象 + Generator 函数 + Generator 迭代器对象 + 数组[] + 对象{} 】
  • 步骤
    • 最外层 Promise
    • 入口 onFilfilled()
    • generator 函数执行到 yield 位置,并执行 yield 的表达式,表达式对应的异步操作的结果通过 next() 返回
    • 继续执行 .then() 内部的 next() => 循环 => 链式调用
    • generator 中的所有的 yield 表达式均执行完毕
    • 执行 return
    • 执行最外层 Promise 的 resolve()
    • co 调用 generator 执行完毕

Co 源码的核心代码

function co(gen) {
  var ctx = this
  var args = slice.call(arguments, 1) // 将 generator 函数的参数作为co的参数
  return new Promise(function (resolve, reject) { // 返回 Promise 的实例
    if (typeof gen === 'function') gen = gen.apply(ctx, args) // 判断generator是否为函数类型
    if (!gen || typeof gen.next !== 'function') return resolve(gen) // 判断是否存在 next() 方法
    onFulfilled() // 入口
    function onFulfilled(res) { // 成功
      var ret
      try {
        ret = gen.next(res) // 获取当前步骤 generator 函数中 yield 表达式返回的值
      } catch (e) {
        return reject(e) // 返回报错
      }
      next(ret) // 链式调用
    }
    function onRejected(err) { // 失败
      var ret
      try {
        ret = gen.throw(err)
      } catch (e) {
        return reject(e)
      }
      next(ret) // 链式调用
    }
    function next(ret) {  // next 方法
        // ... 
    } 
  })
}