generator.js 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. /** @license MIT License (c) copyright 2010-2014 original author or authors */
  2. /** @author Brian Cavalier */
  3. /** @author John Hann */
  4. (function(define) { 'use strict';
  5. define(function(require) {
  6. var when = require('./when');
  7. var slice = Array.prototype.slice;
  8. var Promise = when.Promise;
  9. var reject = Promise.reject;
  10. /**
  11. * Lift a generator to create a function that can suspend and
  12. * resume using the `yield` keyword to await promises.
  13. * @param {function} generator
  14. * @return {function}
  15. */
  16. function lift(generator) {
  17. return function() {
  18. return run(generator, this, arguments);
  19. };
  20. }
  21. /**
  22. * Immediately call a generator as a promise-aware coroutine
  23. * that can suspend and resume using the `yield` keyword to
  24. * await promises. Additional arguments after the first will
  25. * be passed through to the generator.
  26. * @param {function} generator
  27. * @returns {Promise} promise for the ultimate value returned
  28. * from the generator.
  29. */
  30. function call(generator /*x, y, z...*/) {
  31. /*jshint validthis:true*/
  32. return run(generator, this, slice.call(arguments, 1));
  33. }
  34. /**
  35. * Immediately apply a generator, with the supplied args array,
  36. * as a promise-aware coroutine that can suspend and resume
  37. * using the `yield` keyword to await promises.
  38. * @param {function} generator
  39. * @param {Array} args arguments with which to initialize the generator
  40. * @returns {Promise} promise for the ultimate value returned
  41. * from the generator.
  42. */
  43. function apply(generator, args) {
  44. /*jshint validthis:true*/
  45. return run(generator, this, args || []);
  46. }
  47. /**
  48. * Helper to initiate the provided generator as a coroutine
  49. * @returns {*}
  50. */
  51. function run(generator, thisArg, args) {
  52. return runNext(void 0, generator.apply(thisArg, args));
  53. }
  54. function runNext(x, iterator) {
  55. try {
  56. return handle(iterator.next(x), iterator);
  57. } catch(e) {
  58. return reject(e);
  59. }
  60. }
  61. function next(x) {
  62. /*jshint validthis:true*/
  63. return runNext(x, this);
  64. }
  65. function error(e) {
  66. /*jshint validthis:true*/
  67. try {
  68. return handle(this.throw(e), this);
  69. } catch(e) {
  70. return reject(e);
  71. }
  72. }
  73. function handle(result, iterator) {
  74. if(result.done) {
  75. return result.value;
  76. }
  77. var h = Promise._handler(result.value);
  78. if(h.state() > 0) {
  79. return runNext(h.value, iterator);
  80. }
  81. var p = Promise._defer();
  82. h.chain(p._handler, iterator, next, error);
  83. return p;
  84. }
  85. return {
  86. lift: lift,
  87. call: call,
  88. apply: apply
  89. };
  90. });
  91. }(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));