1、co是个啥?
看原文档、稀里哗啦写了一堆,英文也不认识。但是从中可以get出一段关键的信息:“generator函数(生成器函数)的自动执行函数”。
2、疑问?
generator不能自动执行么,还非得要个第三方的库?带着疑问我去看了一下它的基本用法。
function* gen() {yield '1';yield '2';return true;}var iterator = gen();var p1 = iterator.next();var p2 = iterator.next();var p3 = iterator.next();console.log(p1);// {value: '1', done: false}console.log(p2);// {value: '2', done: false}console.log(p3);// {value: true, done: true}
写了一遍发现确实有点麻烦,每次迭代都要.next()才能继续下一步的操作,直到done为true时停止。
3、co是如何解决这个问题的?
经过源码了解co就是根据生成器的特性和Promise结合创造出来的一个自动生成器。也就是说不需要手动的调用next函数,他会根据你传入生成器函数自动的执行next函数,直到done为true为止。
核心代码:
function co(gen) {var ctx = this;var args = slice.call(arguments, 1)return new Promise(function(resolve, reject) {// 把参数传递给gen函数并执行if (typeof gen === 'function') gen = gen.apply(ctx, args);// 如果不是函数 直接返回if (!gen || typeof gen.next !== 'function') return resolve(gen);onFulfilled();//重复执行nextfunction onFulfilled(res) {var ret;try {ret = gen.next(res);} 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) {// 如果done为true,直接返回if (ret.done) return resolve(ret.value);// 将结果封装成promise对象。var value = toPromise.call(ctx, ret.value);// 判断 value 是否为 Promise,如果是就返回 then 继续执行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) + '"'));}});}
到这里基本上就结束了本次的源码之旅,但是还是有些疑问,为什么co内部要用Promise封了一层?
我的感觉就是使用Promise更容易的捕获异常,也就是当任务失败,就执行 onRejected 函数,成功执行 onFullfilled 函数。
4、收获
我觉得本次看源码最大的收货就是学会了一些判断类型的小技巧。
例如Promise是这样判断的。
function isPromise(obj) {return 'function' == typeof obj.then;}
判断对象还有这种操作?
function isObject(val) {return Object == val.constructor;}
头一次接触generator判断。
function isGenerator(obj) {return 'function' == typeof obj.next && 'function' == typeof obj.throw;}
还有一些call的使用,之前不太会用。
5、感想
读源码感觉就像发现新大陆一样,原来代码还可以这样写!!!
可以开阔自己的视野,虽然看的是一篇源码,但是在看之前也需要补充大量的相关知识,完善自己的知识体系,最重要的是可以灵活的运用在自己的项目中,对自己是一个不错的提升。
6、参考链接
1、https://github.com/mqyqingfeng/Blog/issues/99 ES6 系列之 Generator 的自动执行
2、https://juejin.cn/post/6844904088220467213 学习 koa 源码的整体架构,浅析koa洋葱模型原理和co原理
