map.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. "use strict";
  2. module.exports = function(Promise,
  3. PromiseArray,
  4. apiRejection,
  5. tryConvertToPromise,
  6. INTERNAL,
  7. debug) {
  8. var getDomain = Promise._getDomain;
  9. var util = require("./util");
  10. var tryCatch = util.tryCatch;
  11. var errorObj = util.errorObj;
  12. var async = Promise._async;
  13. function MappingPromiseArray(promises, fn, limit, _filter) {
  14. this.constructor$(promises);
  15. this._promise._captureStackTrace();
  16. var domain = getDomain();
  17. this._callback = domain === null ? fn : util.domainBind(domain, fn);
  18. this._preservedValues = _filter === INTERNAL
  19. ? new Array(this.length())
  20. : null;
  21. this._limit = limit;
  22. this._inFlight = 0;
  23. this._queue = [];
  24. async.invoke(this._asyncInit, this, undefined);
  25. }
  26. util.inherits(MappingPromiseArray, PromiseArray);
  27. MappingPromiseArray.prototype._asyncInit = function() {
  28. this._init$(undefined, -2);
  29. };
  30. MappingPromiseArray.prototype._init = function () {};
  31. MappingPromiseArray.prototype._promiseFulfilled = function (value, index) {
  32. var values = this._values;
  33. var length = this.length();
  34. var preservedValues = this._preservedValues;
  35. var limit = this._limit;
  36. if (index < 0) {
  37. index = (index * -1) - 1;
  38. values[index] = value;
  39. if (limit >= 1) {
  40. this._inFlight--;
  41. this._drainQueue();
  42. if (this._isResolved()) return true;
  43. }
  44. } else {
  45. if (limit >= 1 && this._inFlight >= limit) {
  46. values[index] = value;
  47. this._queue.push(index);
  48. return false;
  49. }
  50. if (preservedValues !== null) preservedValues[index] = value;
  51. var promise = this._promise;
  52. var callback = this._callback;
  53. var receiver = promise._boundValue();
  54. promise._pushContext();
  55. var ret = tryCatch(callback).call(receiver, value, index, length);
  56. var promiseCreated = promise._popContext();
  57. debug.checkForgottenReturns(
  58. ret,
  59. promiseCreated,
  60. preservedValues !== null ? "Promise.filter" : "Promise.map",
  61. promise
  62. );
  63. if (ret === errorObj) {
  64. this._reject(ret.e);
  65. return true;
  66. }
  67. var maybePromise = tryConvertToPromise(ret, this._promise);
  68. if (maybePromise instanceof Promise) {
  69. maybePromise = maybePromise._target();
  70. var bitField = maybePromise._bitField;
  71. ;
  72. if (((bitField & 50397184) === 0)) {
  73. if (limit >= 1) this._inFlight++;
  74. values[index] = maybePromise;
  75. maybePromise._proxy(this, (index + 1) * -1);
  76. return false;
  77. } else if (((bitField & 33554432) !== 0)) {
  78. ret = maybePromise._value();
  79. } else if (((bitField & 16777216) !== 0)) {
  80. this._reject(maybePromise._reason());
  81. return true;
  82. } else {
  83. this._cancel();
  84. return true;
  85. }
  86. }
  87. values[index] = ret;
  88. }
  89. var totalResolved = ++this._totalResolved;
  90. if (totalResolved >= length) {
  91. if (preservedValues !== null) {
  92. this._filter(values, preservedValues);
  93. } else {
  94. this._resolve(values);
  95. }
  96. return true;
  97. }
  98. return false;
  99. };
  100. MappingPromiseArray.prototype._drainQueue = function () {
  101. var queue = this._queue;
  102. var limit = this._limit;
  103. var values = this._values;
  104. while (queue.length > 0 && this._inFlight < limit) {
  105. if (this._isResolved()) return;
  106. var index = queue.pop();
  107. this._promiseFulfilled(values[index], index);
  108. }
  109. };
  110. MappingPromiseArray.prototype._filter = function (booleans, values) {
  111. var len = values.length;
  112. var ret = new Array(len);
  113. var j = 0;
  114. for (var i = 0; i < len; ++i) {
  115. if (booleans[i]) ret[j++] = values[i];
  116. }
  117. ret.length = j;
  118. this._resolve(ret);
  119. };
  120. MappingPromiseArray.prototype.preservedValues = function () {
  121. return this._preservedValues;
  122. };
  123. function map(promises, fn, options, _filter) {
  124. if (typeof fn !== "function") {
  125. return apiRejection("expecting a function but got " + util.classString(fn));
  126. }
  127. var limit = 0;
  128. if (options !== undefined) {
  129. if (typeof options === "object" && options !== null) {
  130. if (typeof options.concurrency !== "number") {
  131. return Promise.reject(
  132. new TypeError("'concurrency' must be a number but it is " +
  133. util.classString(options.concurrency)));
  134. }
  135. limit = options.concurrency;
  136. } else {
  137. return Promise.reject(new TypeError(
  138. "options argument must be an object but it is " +
  139. util.classString(options)));
  140. }
  141. }
  142. limit = typeof limit === "number" &&
  143. isFinite(limit) && limit >= 1 ? limit : 0;
  144. return new MappingPromiseArray(promises, fn, limit, _filter).promise();
  145. }
  146. Promise.prototype.map = function (fn, options) {
  147. return map(this, fn, options, null);
  148. };
  149. Promise.map = function (promises, fn, options, _filter) {
  150. return map(promises, fn, options, _filter);
  151. };
  152. };