Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- 'use strict';
- /*global console*/
- var len = 1000, times = 1000;
- var tasks = [];
- function task(callback) {
- callback();
- }
- for (var i = 0; i < len; i++) tasks[i] = task;
- function *testBody() {
- for (var i = 0; i < len; i++) yield task;
- yield tasks;
- }
- var v3 = coV3(), v4 = coV4();
- v3(function *(){
- var i;
- console.time('co v3 test1');
- for (i = 0; i < times; i++) yield v3(testBody);
- console.timeEnd('co v3 test1');
- console.time('co v4 test1');
- for (i = 0; i < times; i++) yield v4(testBody);
- console.timeEnd('co v4 test1');
- console.time('co v4 test2');
- for (i = 0; i < times; i++) yield v4(testBody);
- console.timeEnd('co v4 test2');
- console.time('co v3 test2');
- for (i = 0; i < times; i++) yield v3(testBody);
- console.timeEnd('co v3 test2');
- })(function () {
- console.log('Test End');
- });
- function coV4() {
- /**
- * slice() reference.
- */
- var slice = Array.prototype.slice;
- /**
- * Expose `co`.
- */
- // module.exports = co;
- /**
- * Wrap the given generator `fn` into a
- * function that returns a promise.
- * This is a separate function so that
- * every `co()` call doesn't create a new,
- * unnecessary closure.
- *
- * @param {GeneratorFunction} fn
- * @return {Function}
- * @api public
- */
- co.wrap = function (fn) {
- return function () {
- return co.call(this, fn.apply(this, arguments));
- };
- };
- /**
- * Execute the generator function or a generator
- * and return a promise.
- *
- * @param {Function} fn
- * @return {Function}
- * @api public
- */
- function co(gen) {
- var ctx = this;
- if (typeof gen === 'function') gen = gen.call(this);
- return onFulfilled();
- /**
- * @param {Mixed} res
- * @return {Promise}
- * @api private
- */
- function onFulfilled(res) {
- var ret;
- try {
- ret = gen.next(res);
- } catch (e) {
- return Promise.reject(e);
- }
- return next(ret);
- }
- /**
- * @param {Error} err
- * @return {Promise}
- * @api private
- */
- function onRejected(err) {
- var ret;
- try {
- ret = gen.throw(err);
- } catch (e) {
- return Promise.reject(e);
- }
- return next(ret);
- }
- /**
- * Get the next value in the generator,
- * return a promise.
- *
- * @param {Object} ret
- * @return {Promise}
- * @api private
- */
- function next(ret) {
- if (ret.done) return Promise.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) + '"'));
- }
- }
- /**
- * Convert a `yield`ed value into a promise.
- *
- * @param {Mixed} obj
- * @return {Promise}
- * @api private
- */
- 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;
- }
- /**
- * Convert a thunk to a promise.
- *
- * @param {Function}
- * @return {Promise}
- * @api private
- */
- 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);
- });
- });
- }
- /**
- * Convert an array of "yieldables" to a promise.
- * Uses `Promise.all()` internally.
- *
- * @param {Array} obj
- * @return {Promise}
- * @api private
- */
- function arrayToPromise(obj) {
- return Promise.all(obj.map(toPromise, this));
- }
- /**
- * Convert an object of "yieldables" to a promise.
- * Uses `Promise.all()` internally.
- *
- * @param {Object} obj
- * @return {Promise}
- * @api private
- */
- 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;
- }));
- }
- }
- /**
- * Check if `obj` is a promise.
- *
- * @param {Object} obj
- * @return {Boolean}
- * @api private
- */
- function isPromise(obj) {
- return 'function' == typeof obj.then;
- }
- /**
- * Check if `obj` is a generator.
- *
- * @param {Mixed} obj
- * @return {Boolean}
- * @api private
- */
- function isGenerator(obj) {
- return 'function' == typeof obj.next && 'function' == typeof obj.throw;
- }
- /**
- * Check if `obj` is a generator function.
- *
- * @param {Mixed} obj
- * @return {Boolean}
- * @api private
- */
- function isGeneratorFunction(obj) {
- var constructor = obj.constructor;
- return constructor && 'GeneratorFunction' == constructor.name;
- }
- /**
- * Check for plain object.
- *
- * @param {Mixed} val
- * @return {Boolean}
- * @api private
- */
- function isObject(val) {
- return Object == val.constructor;
- }
- return co;
- }
- function coV3() {
- /**
- * slice() reference.
- */
- var slice = Array.prototype.slice;
- /**
- * Expose `co`.
- */
- // module.exports = co;
- /**
- * Wrap the given generator `fn` and
- * return a thunk.
- *
- * @param {Function} fn
- * @return {Function}
- * @api public
- */
- function co(fn) {
- var isGenFun = isGeneratorFunction(fn);
- return function (done) {
- var ctx = this;
- // in toThunk() below we invoke co()
- // with a generator, so optimize for
- // this case
- var gen = fn;
- // we only need to parse the arguments
- // if gen is a generator function.
- if (isGenFun) {
- var args = slice.call(arguments), len = args.length;
- var hasCallback = len && 'function' == typeof args[len - 1];
- done = hasCallback ? args.pop() : error;
- gen = fn.apply(this, args);
- } else {
- done = done || error;
- }
- next();
- // #92
- // wrap the callback in a setImmediate
- // so that any of its errors aren't caught by `co`
- function exit(err, res) {
- setImmediate(function(){
- done.call(ctx, err, res);
- });
- }
- function next(err, res) {
- var ret;
- // multiple args
- if (arguments.length > 2) res = slice.call(arguments, 1);
- // error
- if (err) {
- try {
- ret = gen.throw(err);
- } catch (e) {
- return exit(e);
- }
- }
- // ok
- if (!err) {
- try {
- ret = gen.next(res);
- } catch (e) {
- return exit(e);
- }
- }
- // done
- if (ret.done) return exit(null, ret.value);
- // normalize
- ret.value = toThunk(ret.value, ctx);
- // run
- if ('function' == typeof ret.value) {
- var called = false;
- try {
- ret.value.call(ctx, function(){
- if (called) return;
- called = true;
- next.apply(ctx, arguments);
- });
- } catch (e) {
- setImmediate(function(){
- if (called) return;
- called = true;
- next(e);
- });
- }
- return;
- }
- // invalid
- next(new TypeError('You may only yield a function, promise, generator, array, or object, '
- + 'but the following was passed: "' + String(ret.value) + '"'));
- }
- }
- }
- /**
- * Convert `obj` into a normalized thunk.
- *
- * @param {Mixed} obj
- * @param {Mixed} ctx
- * @return {Function}
- * @api private
- */
- function toThunk(obj, ctx) {
- if (isGeneratorFunction(obj)) {
- return co(obj.call(ctx));
- }
- if (isGenerator(obj)) {
- return co(obj);
- }
- if (isPromise(obj)) {
- return promiseToThunk(obj);
- }
- if ('function' == typeof obj) {
- return obj;
- }
- if (isObject(obj) || Array.isArray(obj)) {
- return objectToThunk.call(ctx, obj);
- }
- return obj;
- }
- /**
- * Convert an object of yieldables to a thunk.
- *
- * @param {Object} obj
- * @return {Function}
- * @api private
- */
- function objectToThunk(obj){
- var ctx = this;
- var isArray = Array.isArray(obj);
- return function(done){
- var keys = Object.keys(obj);
- var pending = keys.length;
- var results = isArray
- ? new Array(pending) // predefine the array length
- : new obj.constructor();
- var finished;
- if (!pending) {
- setImmediate(function(){
- done(null, results)
- });
- return;
- }
- // prepopulate object keys to preserve key ordering
- if (!isArray) {
- for (var i = 0; i < pending; i++) {
- results[keys[i]] = undefined;
- }
- }
- for (var i = 0; i < keys.length; i++) {
- run(obj[keys[i]], keys[i]);
- }
- function run(fn, key) {
- if (finished) return;
- try {
- fn = toThunk(fn, ctx);
- if ('function' != typeof fn) {
- results[key] = fn;
- return --pending || done(null, results);
- }
- fn.call(ctx, function(err, res){
- if (finished) return;
- if (err) {
- finished = true;
- return done(err);
- }
- results[key] = res;
- --pending || done(null, results);
- });
- } catch (err) {
- finished = true;
- done(err);
- }
- }
- }
- }
- /**
- * Convert `promise` to a thunk.
- *
- * @param {Object} promise
- * @return {Function}
- * @api private
- */
- function promiseToThunk(promise) {
- return function(fn){
- promise.then(function(res) {
- fn(null, res);
- }, fn);
- }
- }
- /**
- * Check if `obj` is a promise.
- *
- * @param {Object} obj
- * @return {Boolean}
- * @api private
- */
- function isPromise(obj) {
- return obj && 'function' == typeof obj.then;
- }
- /**
- * Check if `obj` is a generator.
- *
- * @param {Mixed} obj
- * @return {Boolean}
- * @api private
- */
- function isGenerator(obj) {
- return obj && 'function' == typeof obj.next && 'function' == typeof obj.throw;
- }
- /**
- * Check if `obj` is a generator function.
- *
- * @param {Mixed} obj
- * @return {Boolean}
- * @api private
- */
- function isGeneratorFunction(obj) {
- return obj && obj.constructor && 'GeneratorFunction' == obj.constructor.name;
- }
- /**
- * Check for plain object.
- *
- * @param {Mixed} val
- * @return {Boolean}
- * @api private
- */
- function isObject(val) {
- return val && Object == val.constructor;
- }
- /**
- * Throw `err` in a new stack.
- *
- * This is used when co() is invoked
- * without supplying a callback, which
- * should only be for demonstrational
- * purposes.
- *
- * @param {Error} err
- * @api private
- */
- function error(err) {
- if (!err) return;
- setImmediate(function(){
- throw err;
- });
- }
- return co;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement