Open maodouchen opened 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; }