generators.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. "use strict";
  2. module.exports = function(Promise,
  3. apiRejection,
  4. INTERNAL,
  5. tryConvertToPromise) {
  6. var errors = require("./errors.js");
  7. var TypeError = errors.TypeError;
  8. var util = require("./util.js");
  9. var errorObj = util.errorObj;
  10. var tryCatch = util.tryCatch;
  11. var yieldHandlers = [];
  12. function promiseFromYieldHandler(value, yieldHandlers, traceParent) {
  13. for (var i = 0; i < yieldHandlers.length; ++i) {
  14. traceParent._pushContext();
  15. var result = tryCatch(yieldHandlers[i])(value);
  16. traceParent._popContext();
  17. if (result === errorObj) {
  18. traceParent._pushContext();
  19. var ret = Promise.reject(errorObj.e);
  20. traceParent._popContext();
  21. return ret;
  22. }
  23. var maybePromise = tryConvertToPromise(result, traceParent);
  24. if (maybePromise instanceof Promise) return maybePromise;
  25. }
  26. return null;
  27. }
  28. function PromiseSpawn(generatorFunction, receiver, yieldHandler, stack) {
  29. var promise = this._promise = new Promise(INTERNAL);
  30. promise._captureStackTrace();
  31. this._stack = stack;
  32. this._generatorFunction = generatorFunction;
  33. this._receiver = receiver;
  34. this._generator = undefined;
  35. this._yieldHandlers = typeof yieldHandler === "function"
  36. ? [yieldHandler].concat(yieldHandlers)
  37. : yieldHandlers;
  38. }
  39. PromiseSpawn.prototype.promise = function () {
  40. return this._promise;
  41. };
  42. PromiseSpawn.prototype._run = function () {
  43. this._generator = this._generatorFunction.call(this._receiver);
  44. this._receiver =
  45. this._generatorFunction = undefined;
  46. this._next(undefined);
  47. };
  48. PromiseSpawn.prototype._continue = function (result) {
  49. if (result === errorObj) {
  50. return this._promise._rejectCallback(result.e, false, true);
  51. }
  52. var value = result.value;
  53. if (result.done === true) {
  54. this._promise._resolveCallback(value);
  55. } else {
  56. var maybePromise = tryConvertToPromise(value, this._promise);
  57. if (!(maybePromise instanceof Promise)) {
  58. maybePromise =
  59. promiseFromYieldHandler(maybePromise,
  60. this._yieldHandlers,
  61. this._promise);
  62. if (maybePromise === null) {
  63. this._throw(
  64. new TypeError(
  65. "A value %s was yielded that could not be treated as a promise\u000a\u000a See http://goo.gl/4Y4pDk\u000a\u000a".replace("%s", value) +
  66. "From coroutine:\u000a" +
  67. this._stack.split("\n").slice(1, -7).join("\n")
  68. )
  69. );
  70. return;
  71. }
  72. }
  73. maybePromise._then(
  74. this._next,
  75. this._throw,
  76. undefined,
  77. this,
  78. null
  79. );
  80. }
  81. };
  82. PromiseSpawn.prototype._throw = function (reason) {
  83. this._promise._attachExtraTrace(reason);
  84. this._promise._pushContext();
  85. var result = tryCatch(this._generator["throw"])
  86. .call(this._generator, reason);
  87. this._promise._popContext();
  88. this._continue(result);
  89. };
  90. PromiseSpawn.prototype._next = function (value) {
  91. this._promise._pushContext();
  92. var result = tryCatch(this._generator.next).call(this._generator, value);
  93. this._promise._popContext();
  94. this._continue(result);
  95. };
  96. Promise.coroutine = function (generatorFunction, options) {
  97. if (typeof generatorFunction !== "function") {
  98. throw new TypeError("generatorFunction must be a function\u000a\u000a See http://goo.gl/6Vqhm0\u000a");
  99. }
  100. var yieldHandler = Object(options).yieldHandler;
  101. var PromiseSpawn$ = PromiseSpawn;
  102. var stack = new Error().stack;
  103. return function () {
  104. var generator = generatorFunction.apply(this, arguments);
  105. var spawn = new PromiseSpawn$(undefined, undefined, yieldHandler,
  106. stack);
  107. spawn._generator = generator;
  108. spawn._next(undefined);
  109. return spawn.promise();
  110. };
  111. };
  112. Promise.coroutine.addYieldHandler = function(fn) {
  113. if (typeof fn !== "function") throw new TypeError("fn must be a function\u000a\u000a See http://goo.gl/916lJJ\u000a");
  114. yieldHandlers.push(fn);
  115. };
  116. Promise.spawn = function (generatorFunction) {
  117. if (typeof generatorFunction !== "function") {
  118. return apiRejection("generatorFunction must be a function\u000a\u000a See http://goo.gl/6Vqhm0\u000a");
  119. }
  120. var spawn = new PromiseSpawn(generatorFunction, this);
  121. var ret = spawn.promise();
  122. spawn._run(Promise.spawn);
  123. return ret;
  124. };
  125. };