co入门

1 什么是CO

co是基于Generator和Promise的异步解决方案,co的最大好处就是允许你以同步的方式写异步的代码流程,并且可以使用try/catch。

2 用法

1
2
3
4
5
6
7
8
co(function *(){
try {
var res = yield fetch(...);
console.log(res);
} catch(e) {
console.log(e)
}
})()

3 源码解读

co的源码只有200多行,还是很短的,那就看看吧。

1
2
3
4
5
6
7
8
9
10
11
function co(gen) {
var ctx = this;
var args = slice.call(arguments, 1)
return new Promise(function(resolve, reject) {
if (typeof gen === 'function') gen = gen.apply(ctx, args);
if (!gen || typeof gen.next !== 'function') return resolve(gen);
onFulfilled();
...
}

可以发现:
co返回的最终结果是一个Promise对象;第6行,这里已经调用gen了,所以下面就可以通过next()遍历了。
然后发现运行了一个叫onFulfilled()的函数,这是什么呢
,往下看就知道了

1
2
3
4
5
6
7
8
9
function onFulfilled(res) {
var ret;
try {
ret = gen.next(res);
} catch (e) {
return reject(e);
}
next(ret);
}

看第四行我知道原来这调用了gen.next()去遍历generator了,同时将返回的结果放倒ret并且当作参数执行了next()函数,这里的next函数并不是gen.next,那这是什么呢?继续看

1
2
3
4
5
6
7
function next(ret) {
if (ret.done) return resolve(ret.value);
var value = toPromise.call(ctx, ret.value);
if (value && isPromise(value)) return value.then(onFulfilled, onRejected);
return onRejected(new TypeError('You may only yield a function, promise, generator, array, or object, '
+ 'but the following object was passed: "' + String(ret.value) + '"'));
}

这个函数首先判断了ret.done ,这是在判断generator是否遍历完成,如果没完成继续向下走,这里又运行了一个toPromise函数,根据名字就知道这是将上一步返回的value转换成Promise对象,然后下一步为这个promise添加了成功和失败回调,如果上一步状态是成功那么就会再去运行onFulfilled()函数,并且把结果传递下去,如果某一步运行失败,那么她就会调用onRejected函数,这是什么呢

1
2
3
4
5
6
7
8
9
function onRejected(err) {
var ret;
try {
ret = gen.throw(err);
} catch (e) {
return reject(e);
}
next(ret);
}

这原来就是对于上一步发生的错误抛出异常便于外层捕获。如果异常抛出成功,就会继续next遍历generator对象直到结束。
这就是co运行的大概流程,下面看一下他所提供的一下其他方法。

1
2
3
4
5
6
function isGeneratorFunction(obj) {
var constructor = obj.constructor;
if (!constructor) return false;
if ('GeneratorFunction' === constructor.name || 'GeneratorFunction' === constructor.displayName) return true;
return isGenerator(constructor.prototype);
}

根据名字就知道这个函数是判断一个函数是否是Generator函数:
首先获取obj的构造函数,如果构造函数没有自然就不是了,然后只要判断构造函数的name活着displayname就可以了

1
2
3
function isPromise(obj) {
return 'function' == typeof obj.then;
}

这个函数的作用是判断一个对象是否是promise对象,那我们只需要判断这个对象里面是否有then函数就可以了