co模块整体包括三部分
-
对于几种参数类型的判断,主要判断是否object,array,promise,generator,generatorFunction这几种;
-
将几种不同的参数类型转换为promise
-
递归执行promise
module.exports = co['default'] = co.co = co; let slice = [].slice; // 多次用到,所以定义成变量; 原文是Array.prototype.slice // 1. 对于几种参数类型的判断,主要判断是否object,array,promise,generator,generatorFunction这几种; /** * 判断是否为对象 * 任何数据类型的constructor属性返回创建该对象的函数的引用,实例的constructor属性指向其构造函数, */ function isObject(obj) { return obj.constructor === Object; } /** * 是否promise * promise具有.then方法,.catch方法 */ function isPromise(obj) { return 'function' === typeof obj.then; //也可以用 obj.constructor === Promise } /** * 是否generator对象, * generator具有next,throw,return方法 */ function isGenerator(obj) { return 'function' === typeof obj.next() && 'function' === typeof obj.throw() && 'function' === typeof obj.return(); } /** * generator的constructor的name为GeneratorFunction,displayName(非标准)如果设置也为* GeneratorFunction, * display相关参考https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/displayName *【注意】generator的constructor !== GeneratorFunction , 参考自这里https://blog.csdn.net/sinat_30552885/article/details/85247120 */ function isGeneratorFunction(obj) { let constructor = obj.constructor; if ( !constructor ) return false; if ( constructor.name === 'GeneratorFunction' || constructor.displayName === 'GeneratorFunction') return true; return isGenerator(obj); } // 2. 将几种不同的参数类型转换为promise // 总括 function toPromise(obj) { if (!obj) return obj; if ( isPromise(obj) ) return obj; if ( isGenerator(obj) || isGeneratorFunction(obj) ) return co.call(this, obj); // co的入参接收promise或者generator,因此如果是generator,则直接调用一遍co; if ( 'function' === typeof obj) return thunkToPromise.call(this, obj); if ( Array.isArray(obj) ) return arrayToPromise.call(this, obj); if ( isObject(obj) ) return objToPromise.call(this, obj); return obj; } /** * thunk => promise */ function thunkToPromise(fn) { let ctx = this; return new Promise(function(resolve, reject) { fn.call(ctx, function(err, res) { if ( err ) reject(err); if ( arguments.length > 2) res = slice.call(arguments,1); resolve(res); }) }) } /** * arr => promise * 将数组的每一元素变成promise,然后放入到promise.all里统一存储 */ function arrayToPromise(arr) { return Promise.all(arr.map(toPromise, this)); } /** * obj => promise; * obj.constructor 返回创建该对象的函数的引用 */ function objToPromise(obj) { let results = new obj.constructor(); let promises = []; let keys = Object.keys(obj); for ( let i = 0; i < keys.length; i++ ) { let key = keys[i]; let promise = toPromise(this, obj[key]); if ( promise && isPromise(promise) ) { defer(promise, key); } else { results[key] = obj[key]; } } return Promise.all(promises).then(function() { return results; }) function defer(promise, key) { promises.push(promise.then(function(res) { results[key] = res; })) } } // 3. 递归执行promise /** * * @param {*} fn 入参是一个promise或者generator * @return Promise; */ function co(gen) { let ctx = this; let args = slice.call(arguments, 1); return new Promise(function(resolve, reject) { if ( typeof gen === 'function') gen = gen.apply(ctx, args); if ( !gen || typeof gen !== 'function' ) resolve(gen); onFulfilled(); function onFulfilled() { let ret; try { ret = gen.next(); } catch (e) { return reject(e); } next(ret); } function onRejected() { let ret; try { ret = gen.throw(); } catch (e) { return reject(e) } next(ret); } function next(ret) { if ( ret.done ) return resolve(ret.value); let value = toPromise.call(this, 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) + '"')); }) } co.wrapper = function(fn) { createPromise.__generatorFunction__ = fn; return createPromise; function createPromise() { return co.call(this, fn.apply(this,arguments)) } }