Co 源码解读

cokoa 中使用到的基础库,用于 Generator
委派执行,并且可以让开发者更方便编写非阻塞的代码。

以下是使用 co 执行的一个例子:

1
2
3
4
5
6
7
8
const co = require('co')
co(function *() {
let rst = yield Promise.resolve(1)
return rst
}).then((value) => {
console.log(value)
})

函数在 co 中执行的整体流程图如下

co 整体执行流程

主要的核心部分是在返回的 Promise 实例中,其的执行流程如下:

co promise process

  1. 判断传入 co 中的 gen 是否为函数,如果是函数,则绑定当前的上下文到 gen 中,并传入 gen 执行时所需要的参数,代码如下,然后进入 2
1
if (typeof gen === 'function') gen = gen.apply(ctx, args);
  1. 如果函数 gen 不是合法的值,或者其不是 Generator function,在 Promise 直接 return resolve(gen),否则进入步骤 3,代码如下:
if (!gen || typeof gen.next !== 'function') return resolve(gen);
  1. 执行在 Promise 中定义的私有函数 onFulfilled

co 中核心部分函数 onFulfilled 的执行流程

co onFulfilled

  1. 首先执行 gen.next(res) (res 在第一次执行时为 undefined),如果执行出错,转入步骤 2,如果成功执行,转入步骤 3
  2. 直接执行 reject(e),并直接返回;
  3. 执行 next(ret),转入步骤 4
  4. 结束 onFulfilled 执行。

onFulfilled 中核心部分是 next(ret),其执行流程如下

co next

  1. 如果在 co 中执行的是 Generator, 并且其已经执行完 res.donetrue,直接将 return resolve(res.value),否则进入步骤 2
  2. 通过调用函数 toPromise,将 res.value 转换为 Promise,然后进入步骤 3
  3. 如果 toPromise 返回的是 Promise,则通过 then 方法求解 return value.then(onFulfilled, onRejected),否则进入步骤 4
  4. toPromise 的返回值是不支持类型,调用 onRejected 打印出 debug 信息,并继续调用函数 next 求解,返回步骤 1 继续执行。

toPromise 支持了下面几种类型,转换到 Promise:

  • Generator function
  • Normal function
  • JavaScript object
  • JavaScript array

以上便是 co 的整个执行流程,通过把 Generator function 放入 Promise 中执行,进一步简化了 JavaScript 的异步代码的编写。