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))
         }
     }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章