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  六石  阅读(287)  评论(0)    收藏  举报