join.js 7.9 KB

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