Advertisement
Guest User

Untitled

a guest
Dec 20th, 2014
158
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.42 KB | None | 0 0
  1. 'use strict';
  2. /*global console*/
  3.  
  4. var len = 1000, times = 1000;
  5. var tasks = [];
  6.  
  7. function task(callback) {
  8. callback();
  9. }
  10.  
  11. for (var i = 0; i < len; i++) tasks[i] = task;
  12.  
  13. function *testBody() {
  14. for (var i = 0; i < len; i++) yield task;
  15. yield tasks;
  16. }
  17.  
  18. var v3 = coV3(), v4 = coV4();
  19.  
  20. v3(function *(){
  21. var i;
  22.  
  23. console.time('co v3 test1');
  24. for (i = 0; i < times; i++) yield v3(testBody);
  25. console.timeEnd('co v3 test1');
  26.  
  27. console.time('co v4 test1');
  28. for (i = 0; i < times; i++) yield v4(testBody);
  29. console.timeEnd('co v4 test1');
  30.  
  31. console.time('co v4 test2');
  32. for (i = 0; i < times; i++) yield v4(testBody);
  33. console.timeEnd('co v4 test2');
  34.  
  35. console.time('co v3 test2');
  36. for (i = 0; i < times; i++) yield v3(testBody);
  37. console.timeEnd('co v3 test2');
  38.  
  39. })(function () {
  40. console.log('Test End');
  41. });
  42.  
  43. function coV4() {
  44.  
  45. /**
  46. * slice() reference.
  47. */
  48.  
  49. var slice = Array.prototype.slice;
  50.  
  51. /**
  52. * Expose `co`.
  53. */
  54.  
  55. // module.exports = co;
  56.  
  57. /**
  58. * Wrap the given generator `fn` into a
  59. * function that returns a promise.
  60. * This is a separate function so that
  61. * every `co()` call doesn't create a new,
  62. * unnecessary closure.
  63. *
  64. * @param {GeneratorFunction} fn
  65. * @return {Function}
  66. * @api public
  67. */
  68.  
  69. co.wrap = function (fn) {
  70. return function () {
  71. return co.call(this, fn.apply(this, arguments));
  72. };
  73. };
  74.  
  75. /**
  76. * Execute the generator function or a generator
  77. * and return a promise.
  78. *
  79. * @param {Function} fn
  80. * @return {Function}
  81. * @api public
  82. */
  83.  
  84. function co(gen) {
  85. var ctx = this;
  86. if (typeof gen === 'function') gen = gen.call(this);
  87. return onFulfilled();
  88.  
  89. /**
  90. * @param {Mixed} res
  91. * @return {Promise}
  92. * @api private
  93. */
  94.  
  95. function onFulfilled(res) {
  96. var ret;
  97. try {
  98. ret = gen.next(res);
  99. } catch (e) {
  100. return Promise.reject(e);
  101. }
  102. return next(ret);
  103. }
  104.  
  105. /**
  106. * @param {Error} err
  107. * @return {Promise}
  108. * @api private
  109. */
  110.  
  111. function onRejected(err) {
  112. var ret;
  113. try {
  114. ret = gen.throw(err);
  115. } catch (e) {
  116. return Promise.reject(e);
  117. }
  118. return next(ret);
  119. }
  120.  
  121. /**
  122. * Get the next value in the generator,
  123. * return a promise.
  124. *
  125. * @param {Object} ret
  126. * @return {Promise}
  127. * @api private
  128. */
  129.  
  130. function next(ret) {
  131. if (ret.done) return Promise.resolve(ret.value);
  132. var value = toPromise.call(ctx, ret.value);
  133. if (value && isPromise(value)) return value.then(onFulfilled, onRejected);
  134. return onRejected(new TypeError('You may only yield a function, promise, generator, array, or object, '
  135. + 'but the following object was passed: "' + String(ret.value) + '"'));
  136. }
  137. }
  138.  
  139. /**
  140. * Convert a `yield`ed value into a promise.
  141. *
  142. * @param {Mixed} obj
  143. * @return {Promise}
  144. * @api private
  145. */
  146.  
  147. function toPromise(obj) {
  148. if (!obj) return obj;
  149. if (isPromise(obj)) return obj;
  150. if (isGeneratorFunction(obj) || isGenerator(obj)) return co.call(this, obj);
  151. if ('function' == typeof obj) return thunkToPromise.call(this, obj);
  152. if (Array.isArray(obj)) return arrayToPromise.call(this, obj);
  153. if (isObject(obj)) return objectToPromise.call(this, obj);
  154. return obj;
  155. }
  156.  
  157. /**
  158. * Convert a thunk to a promise.
  159. *
  160. * @param {Function}
  161. * @return {Promise}
  162. * @api private
  163. */
  164.  
  165. function thunkToPromise(fn) {
  166. var ctx = this;
  167. return new Promise(function (resolve, reject) {
  168. fn.call(ctx, function (err, res) {
  169. if (err) return reject(err);
  170. if (arguments.length > 2) res = slice.call(arguments, 1);
  171. resolve(res);
  172. });
  173. });
  174. }
  175.  
  176. /**
  177. * Convert an array of "yieldables" to a promise.
  178. * Uses `Promise.all()` internally.
  179. *
  180. * @param {Array} obj
  181. * @return {Promise}
  182. * @api private
  183. */
  184.  
  185. function arrayToPromise(obj) {
  186. return Promise.all(obj.map(toPromise, this));
  187. }
  188.  
  189. /**
  190. * Convert an object of "yieldables" to a promise.
  191. * Uses `Promise.all()` internally.
  192. *
  193. * @param {Object} obj
  194. * @return {Promise}
  195. * @api private
  196. */
  197.  
  198. function objectToPromise(obj){
  199. var results = new obj.constructor();
  200. var keys = Object.keys(obj);
  201. var promises = [];
  202. for (var i = 0; i < keys.length; i++) {
  203. var key = keys[i];
  204. var promise = toPromise.call(this, obj[key]);
  205. if (promise && isPromise(promise)) defer(promise, key);
  206. else results[key] = obj[key];
  207. }
  208. return Promise.all(promises).then(function () {
  209. return results;
  210. });
  211.  
  212. function defer(promise, key) {
  213. // predefine the key in the result
  214. results[key] = undefined;
  215. promises.push(promise.then(function (res) {
  216. results[key] = res;
  217. }));
  218. }
  219. }
  220.  
  221. /**
  222. * Check if `obj` is a promise.
  223. *
  224. * @param {Object} obj
  225. * @return {Boolean}
  226. * @api private
  227. */
  228.  
  229. function isPromise(obj) {
  230. return 'function' == typeof obj.then;
  231. }
  232.  
  233. /**
  234. * Check if `obj` is a generator.
  235. *
  236. * @param {Mixed} obj
  237. * @return {Boolean}
  238. * @api private
  239. */
  240.  
  241. function isGenerator(obj) {
  242. return 'function' == typeof obj.next && 'function' == typeof obj.throw;
  243. }
  244.  
  245. /**
  246. * Check if `obj` is a generator function.
  247. *
  248. * @param {Mixed} obj
  249. * @return {Boolean}
  250. * @api private
  251. */
  252.  
  253. function isGeneratorFunction(obj) {
  254. var constructor = obj.constructor;
  255. return constructor && 'GeneratorFunction' == constructor.name;
  256. }
  257.  
  258. /**
  259. * Check for plain object.
  260. *
  261. * @param {Mixed} val
  262. * @return {Boolean}
  263. * @api private
  264. */
  265.  
  266. function isObject(val) {
  267. return Object == val.constructor;
  268. }
  269.  
  270. return co;
  271.  
  272. }
  273.  
  274.  
  275. function coV3() {
  276.  
  277. /**
  278. * slice() reference.
  279. */
  280.  
  281. var slice = Array.prototype.slice;
  282.  
  283. /**
  284. * Expose `co`.
  285. */
  286.  
  287. // module.exports = co;
  288.  
  289. /**
  290. * Wrap the given generator `fn` and
  291. * return a thunk.
  292. *
  293. * @param {Function} fn
  294. * @return {Function}
  295. * @api public
  296. */
  297.  
  298. function co(fn) {
  299. var isGenFun = isGeneratorFunction(fn);
  300.  
  301. return function (done) {
  302. var ctx = this;
  303.  
  304. // in toThunk() below we invoke co()
  305. // with a generator, so optimize for
  306. // this case
  307. var gen = fn;
  308.  
  309. // we only need to parse the arguments
  310. // if gen is a generator function.
  311. if (isGenFun) {
  312. var args = slice.call(arguments), len = args.length;
  313. var hasCallback = len && 'function' == typeof args[len - 1];
  314. done = hasCallback ? args.pop() : error;
  315. gen = fn.apply(this, args);
  316. } else {
  317. done = done || error;
  318. }
  319.  
  320. next();
  321.  
  322. // #92
  323. // wrap the callback in a setImmediate
  324. // so that any of its errors aren't caught by `co`
  325. function exit(err, res) {
  326. setImmediate(function(){
  327. done.call(ctx, err, res);
  328. });
  329. }
  330.  
  331. function next(err, res) {
  332. var ret;
  333.  
  334. // multiple args
  335. if (arguments.length > 2) res = slice.call(arguments, 1);
  336.  
  337. // error
  338. if (err) {
  339. try {
  340. ret = gen.throw(err);
  341. } catch (e) {
  342. return exit(e);
  343. }
  344. }
  345.  
  346. // ok
  347. if (!err) {
  348. try {
  349. ret = gen.next(res);
  350. } catch (e) {
  351. return exit(e);
  352. }
  353. }
  354.  
  355. // done
  356. if (ret.done) return exit(null, ret.value);
  357.  
  358. // normalize
  359. ret.value = toThunk(ret.value, ctx);
  360.  
  361. // run
  362. if ('function' == typeof ret.value) {
  363. var called = false;
  364. try {
  365. ret.value.call(ctx, function(){
  366. if (called) return;
  367. called = true;
  368. next.apply(ctx, arguments);
  369. });
  370. } catch (e) {
  371. setImmediate(function(){
  372. if (called) return;
  373. called = true;
  374. next(e);
  375. });
  376. }
  377. return;
  378. }
  379.  
  380. // invalid
  381. next(new TypeError('You may only yield a function, promise, generator, array, or object, '
  382. + 'but the following was passed: "' + String(ret.value) + '"'));
  383. }
  384. }
  385. }
  386.  
  387. /**
  388. * Convert `obj` into a normalized thunk.
  389. *
  390. * @param {Mixed} obj
  391. * @param {Mixed} ctx
  392. * @return {Function}
  393. * @api private
  394. */
  395.  
  396. function toThunk(obj, ctx) {
  397.  
  398. if (isGeneratorFunction(obj)) {
  399. return co(obj.call(ctx));
  400. }
  401.  
  402. if (isGenerator(obj)) {
  403. return co(obj);
  404. }
  405.  
  406. if (isPromise(obj)) {
  407. return promiseToThunk(obj);
  408. }
  409.  
  410. if ('function' == typeof obj) {
  411. return obj;
  412. }
  413.  
  414. if (isObject(obj) || Array.isArray(obj)) {
  415. return objectToThunk.call(ctx, obj);
  416. }
  417.  
  418. return obj;
  419. }
  420.  
  421. /**
  422. * Convert an object of yieldables to a thunk.
  423. *
  424. * @param {Object} obj
  425. * @return {Function}
  426. * @api private
  427. */
  428.  
  429. function objectToThunk(obj){
  430. var ctx = this;
  431. var isArray = Array.isArray(obj);
  432.  
  433. return function(done){
  434. var keys = Object.keys(obj);
  435. var pending = keys.length;
  436. var results = isArray
  437. ? new Array(pending) // predefine the array length
  438. : new obj.constructor();
  439. var finished;
  440.  
  441. if (!pending) {
  442. setImmediate(function(){
  443. done(null, results)
  444. });
  445. return;
  446. }
  447.  
  448. // prepopulate object keys to preserve key ordering
  449. if (!isArray) {
  450. for (var i = 0; i < pending; i++) {
  451. results[keys[i]] = undefined;
  452. }
  453. }
  454.  
  455. for (var i = 0; i < keys.length; i++) {
  456. run(obj[keys[i]], keys[i]);
  457. }
  458.  
  459. function run(fn, key) {
  460. if (finished) return;
  461. try {
  462. fn = toThunk(fn, ctx);
  463.  
  464. if ('function' != typeof fn) {
  465. results[key] = fn;
  466. return --pending || done(null, results);
  467. }
  468.  
  469. fn.call(ctx, function(err, res){
  470. if (finished) return;
  471.  
  472. if (err) {
  473. finished = true;
  474. return done(err);
  475. }
  476.  
  477. results[key] = res;
  478. --pending || done(null, results);
  479. });
  480. } catch (err) {
  481. finished = true;
  482. done(err);
  483. }
  484. }
  485. }
  486. }
  487.  
  488. /**
  489. * Convert `promise` to a thunk.
  490. *
  491. * @param {Object} promise
  492. * @return {Function}
  493. * @api private
  494. */
  495.  
  496. function promiseToThunk(promise) {
  497. return function(fn){
  498. promise.then(function(res) {
  499. fn(null, res);
  500. }, fn);
  501. }
  502. }
  503.  
  504. /**
  505. * Check if `obj` is a promise.
  506. *
  507. * @param {Object} obj
  508. * @return {Boolean}
  509. * @api private
  510. */
  511.  
  512. function isPromise(obj) {
  513. return obj && 'function' == typeof obj.then;
  514. }
  515.  
  516. /**
  517. * Check if `obj` is a generator.
  518. *
  519. * @param {Mixed} obj
  520. * @return {Boolean}
  521. * @api private
  522. */
  523.  
  524. function isGenerator(obj) {
  525. return obj && 'function' == typeof obj.next && 'function' == typeof obj.throw;
  526. }
  527.  
  528. /**
  529. * Check if `obj` is a generator function.
  530. *
  531. * @param {Mixed} obj
  532. * @return {Boolean}
  533. * @api private
  534. */
  535.  
  536. function isGeneratorFunction(obj) {
  537. return obj && obj.constructor && 'GeneratorFunction' == obj.constructor.name;
  538. }
  539.  
  540. /**
  541. * Check for plain object.
  542. *
  543. * @param {Mixed} val
  544. * @return {Boolean}
  545. * @api private
  546. */
  547.  
  548. function isObject(val) {
  549. return val && Object == val.constructor;
  550. }
  551.  
  552. /**
  553. * Throw `err` in a new stack.
  554. *
  555. * This is used when co() is invoked
  556. * without supplying a callback, which
  557. * should only be for demonstrational
  558. * purposes.
  559. *
  560. * @param {Error} err
  561. * @api private
  562. */
  563.  
  564. function error(err) {
  565. if (!err) return;
  566. setImmediate(function(){
  567. throw err;
  568. });
  569. }
  570.  
  571. return co;
  572.  
  573. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement