maodouchen / note

学习笔记
0 stars 0 forks source link

generator/co/trunk #23

Open maodouchen opened 5 years ago

maodouchen commented 5 years ago
// 通用一点的trunkify
function thunkify (fn) {
    return function () {
        let arg = Array.prototype.slice.call(null, arguments)
        return function (cb) {
            arg.push(cb);
            fn.apply(null, arg);
        }
    }
}
// trunk 变成传入单参数的函数
var fs = require('fs');
function readFile(file) {
    return function (cb) {
        fs.readFile(file, 'utf-8', cb);
    }
}
// co 自动化的异步调用
co(function * () {
    var a = yield readFile('error.js', 'utf-8');
    var b = yield readFile('package.json', 'utf-8');
    return {a, b}
}).then(function (file1, file2) {
    console.log(file1);
    console.log(file2);
})
// co源码
var slice = Array.prototype.slice;

module.exports = co['default'] = co.co = co;

co.wrap = function (fn) {
    createPromise.__generatorFunction__ = fn;
    return createPromise;
    function createPromise() {
        return co.call(this, fn.apply(this, arguments));
    }
};

// 返回promise对象,调用next方法, 如果done=false 就将value值变成promise对象 value.then(后继续调用next)  知道done变成true
function co(gen) {
    var ctx = this;
    var args = slice.call(arguments, 1);

    return new Promise(function(resolve, reject) {
        if (typeof gen === 'function') gen = gen.apply(ctx, args);
        if (!gen || typeof gen.next !== 'function') return resolve(gen);

        onFulfilled();

        function onFulfilled(res) {
            var ret;
            try {
                ret = gen.next(res); // 执行next
            } catch (e) {
                return reject(e);
            }
            next(ret);
            return null;
        }

        function onRejected(err) {
            var ret;
            try {
                ret = gen.throw(err);
            } catch (e) {
                return reject(e);
            }
            next(ret);
        }

        // 如果结束直接返回promise对象
        function next(ret) {
            if (ret.done) return resolve(ret.value);
            var value = toPromise.call(ctx, 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) + '"'));
        }
    });
}

// 如果是promise直接返回; 如果是generator 则重新调用co; 如果是function 调用函数 返回一个promise对象
// 如果是个数组  promise.all包裹数组 ;如果是对象 用promise.all包裹对象 ;

function toPromise(obj) {
    if (!obj) return obj;
    if (isPromise(obj)) return obj;
    if (isGeneratorFunction(obj) || isGenerator(obj)) return co.call(this, obj);
    if ('function' == typeof obj) return thunkToPromise.call(this, obj);
    if (Array.isArray(obj)) return arrayToPromise.call(this, obj);
    if (isObject(obj)) return objectToPromise.call(this, obj);
    return obj;
}

// 后面的fn.call(ctx, callback) 就是通用的回调函数  这也是为什么yield后面如果是个function一定得是个trunk的
// 因为只会往里传一个回调函数 在这个回调函数中resolve reject 然后继续执行下面的yield
function thunkToPromise(fn) {
    var ctx = this;
    return new Promise(function (resolve, reject) {
        fn.call(ctx, function (err, res) {
            if (err) return reject(err);
            if (arguments.length > 2) res = slice.call(arguments, 1);
            resolve(res);
        });
    });
}

function arrayToPromise(obj) {
    return Promise.all(obj.map(toPromise, this))
}

function objectToPromise(obj){
    var results = new obj.constructor();
    var keys = Object.keys(obj);
    var promises = [];
    for (var i = 0; i < keys.length; i++) {
        var key = keys[i];
        var promise = toPromise.call(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) {
        // predefine the key in the result
        results[key] = undefined;
        promises.push(promise.then(function (res) {
            results[key] = res;
        }));
    }
}

// 检测是否是promise对象
function isPromise(obj) {
    return 'function' == typeof obj.then;
}

function isGenerator(obj) {
    return 'function' == typeof obj.next && 'function' == typeof obj.throw;
}

// 检测是否是generator函数
function isGeneratorFunction(obj) {
    var constructor = obj.constructor;
    if (!constructor) return false;
    if ('GeneratorFunction' === constructor.name || 'GeneratorFunction' === constructor.displayName) return true;
    return isGenerator(constructor.prototype);
}

function isObject(val) {
    return Object == val.constructor;
}