co源码

co模块整体包括三部分

  1. 对于几种参数类型的判断,主要判断是否object,array,promise,generator,generatorFunction这几种;

  2. 将几种不同的参数类型转换为promise

  3. 递归执行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))
         }
     }
    
posted @ 2019-05-05 15:52  六石  阅读(268)  评论(0编辑  收藏  举报