join.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. "use strict";
  2. module.exports =
  3. function(Promise, PromiseArray, tryConvertToPromise, INTERNAL, async,
  4. getDomain) {
  5. var util = require("./util");
  6. var canEvaluate = util.canEvaluate;
  7. var tryCatch = util.tryCatch;
  8. var errorObj = util.errorObj;
  9. var reject;
  10. if (!false) {
  11. if (canEvaluate) {
  12. var thenCallback = function(i) {
  13. return new Function("value", "holder", " \n\
  14. 'use strict'; \n\
  15. holder.pIndex = value; \n\
  16. holder.checkFulfillment(this); \n\
  17. ".replace(/Index/g, i));
  18. };
  19. var promiseSetter = function(i) {
  20. return new Function("promise", "holder", " \n\
  21. 'use strict'; \n\
  22. holder.pIndex = promise; \n\
  23. ".replace(/Index/g, i));
  24. };
  25. var generateHolderClass = function(total) {
  26. var props = new Array(total);
  27. for (var i = 0; i < props.length; ++i) {
  28. props[i] = "this.p" + (i+1);
  29. }
  30. var assignment = props.join(" = ") + " = null;";
  31. var cancellationCode= "var promise;\n" + props.map(function(prop) {
  32. return " \n\
  33. promise = " + prop + "; \n\
  34. if (promise instanceof Promise) { \n\
  35. promise.cancel(); \n\
  36. } \n\
  37. ";
  38. }).join("\n");
  39. var passedArguments = props.join(", ");
  40. var name = "Holder$" + total;
  41. var code = "return function(tryCatch, errorObj, Promise, async) { \n\
  42. 'use strict'; \n\
  43. function [TheName](fn) { \n\
  44. [TheProperties] \n\
  45. this.fn = fn; \n\
  46. this.asyncNeeded = true; \n\
  47. this.now = 0; \n\
  48. } \n\
  49. \n\
  50. [TheName].prototype._callFunction = function(promise) { \n\
  51. promise._pushContext(); \n\
  52. var ret = tryCatch(this.fn)([ThePassedArguments]); \n\
  53. promise._popContext(); \n\
  54. if (ret === errorObj) { \n\
  55. promise._rejectCallback(ret.e, false); \n\
  56. } else { \n\
  57. promise._resolveCallback(ret); \n\
  58. } \n\
  59. }; \n\
  60. \n\
  61. [TheName].prototype.checkFulfillment = function(promise) { \n\
  62. var now = ++this.now; \n\
  63. if (now === [TheTotal]) { \n\
  64. if (this.asyncNeeded) { \n\
  65. async.invoke(this._callFunction, this, promise); \n\
  66. } else { \n\
  67. this._callFunction(promise); \n\
  68. } \n\
  69. \n\
  70. } \n\
  71. }; \n\
  72. \n\
  73. [TheName].prototype._resultCancelled = function() { \n\
  74. [CancellationCode] \n\
  75. }; \n\
  76. \n\
  77. return [TheName]; \n\
  78. }(tryCatch, errorObj, Promise, async); \n\
  79. ";
  80. code = code.replace(/\[TheName\]/g, name)
  81. .replace(/\[TheTotal\]/g, total)
  82. .replace(/\[ThePassedArguments\]/g, passedArguments)
  83. .replace(/\[TheProperties\]/g, assignment)
  84. .replace(/\[CancellationCode\]/g, cancellationCode);
  85. return new Function("tryCatch", "errorObj", "Promise", "async", code)
  86. (tryCatch, errorObj, Promise, async);
  87. };
  88. var holderClasses = [];
  89. var thenCallbacks = [];
  90. var promiseSetters = [];
  91. for (var i = 0; i < 8; ++i) {
  92. holderClasses.push(generateHolderClass(i + 1));
  93. thenCallbacks.push(thenCallback(i + 1));
  94. promiseSetters.push(promiseSetter(i + 1));
  95. }
  96. reject = function (reason) {
  97. this._reject(reason);
  98. };
  99. }}
  100. Promise.join = function () {
  101. var last = arguments.length - 1;
  102. var fn;
  103. if (last > 0 && typeof arguments[last] === "function") {
  104. fn = arguments[last];
  105. if (!false) {
  106. if (last <= 8 && canEvaluate) {
  107. var ret = new Promise(INTERNAL);
  108. ret._captureStackTrace();
  109. var HolderClass = holderClasses[last - 1];
  110. var holder = new HolderClass(fn);
  111. var callbacks = thenCallbacks;
  112. for (var i = 0; i < last; ++i) {
  113. var maybePromise = tryConvertToPromise(arguments[i], ret);
  114. if (maybePromise instanceof Promise) {
  115. maybePromise = maybePromise._target();
  116. var bitField = maybePromise._bitField;
  117. ;
  118. if (((bitField & 50397184) === 0)) {
  119. maybePromise._then(callbacks[i], reject,
  120. undefined, ret, holder);
  121. promiseSetters[i](maybePromise, holder);
  122. holder.asyncNeeded = false;
  123. } else if (((bitField & 33554432) !== 0)) {
  124. callbacks[i].call(ret,
  125. maybePromise._value(), holder);
  126. } else if (((bitField & 16777216) !== 0)) {
  127. ret._reject(maybePromise._reason());
  128. } else {
  129. ret._cancel();
  130. }
  131. } else {
  132. callbacks[i].call(ret, maybePromise, holder);
  133. }
  134. }
  135. if (!ret._isFateSealed()) {
  136. if (holder.asyncNeeded) {
  137. var domain = getDomain();
  138. if (domain !== null) {
  139. holder.fn = util.domainBind(domain, holder.fn);
  140. }
  141. }
  142. ret._setAsyncGuaranteed();
  143. ret._setOnCancel(holder);
  144. }
  145. return ret;
  146. }
  147. }
  148. }
  149. var $_len = arguments.length;var args = new Array($_len); for(var $_i = 0; $_i < $_len; ++$_i) {args[$_i] = arguments[$_i];};
  150. if (fn) args.pop();
  151. var ret = new PromiseArray(args).promise();
  152. return fn !== undefined ? ret.spread(fn) : ret;
  153. };
  154. };