map.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  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 EMPTY_ARRAY = [];
  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 : domain.bind(fn);
  18. this._preservedValues = _filter === INTERNAL
  19. ? new Array(this.length())
  20. : null;
  21. this._limit = limit;
  22. this._inFlight = 0;
  23. this._queue = limit >= 1 ? [] : EMPTY_ARRAY;
  24. this._init$(undefined, -2);
  25. }
  26. util.inherits(MappingPromiseArray, PromiseArray);
  27. MappingPromiseArray.prototype._init = function () {};
  28. MappingPromiseArray.prototype._promiseFulfilled = function (value, index) {
  29. var values = this._values;
  30. var length = this.length();
  31. var preservedValues = this._preservedValues;
  32. var limit = this._limit;
  33. if (index < 0) {
  34. index = (index * -1) - 1;
  35. values[index] = value;
  36. if (limit >= 1) {
  37. this._inFlight--;
  38. this._drainQueue();
  39. if (this._isResolved()) return true;
  40. }
  41. } else {
  42. if (limit >= 1 && this._inFlight >= limit) {
  43. values[index] = value;
  44. this._queue.push(index);
  45. return false;
  46. }
  47. if (preservedValues !== null) preservedValues[index] = value;
  48. var promise = this._promise;
  49. var callback = this._callback;
  50. var receiver = promise._boundValue();
  51. promise._pushContext();
  52. var ret = tryCatch(callback).call(receiver, value, index, length);
  53. var promiseCreated = promise._popContext();
  54. debug.checkForgottenReturns(
  55. ret,
  56. promiseCreated,
  57. preservedValues !== null ? "Promise.filter" : "Promise.map",
  58. promise
  59. );
  60. if (ret === errorObj) {
  61. this._reject(ret.e);
  62. return true;
  63. }
  64. var maybePromise = tryConvertToPromise(ret, this._promise);
  65. if (maybePromise instanceof Promise) {
  66. maybePromise = maybePromise._target();
  67. var bitField = maybePromise._bitField;
  68. ;
  69. if (((bitField & 50397184) === 0)) {
  70. if (limit >= 1) this._inFlight++;
  71. values[index] = maybePromise;
  72. maybePromise._proxy(this, (index + 1) * -1);
  73. return false;
  74. } else if (((bitField & 33554432) !== 0)) {
  75. ret = maybePromise._value();
  76. } else if (((bitField & 16777216) !== 0)) {
  77. this._reject(maybePromise._reason());
  78. return true;
  79. } else {
  80. this._cancel();
  81. return true;
  82. }
  83. }
  84. values[index] = ret;
  85. }
  86. var totalResolved = ++this._totalResolved;
  87. if (totalResolved >= length) {
  88. if (preservedValues !== null) {
  89. this._filter(values, preservedValues);
  90. } else {
  91. this._resolve(values);
  92. }
  93. return true;
  94. }
  95. return false;
  96. };
  97. MappingPromiseArray.prototype._drainQueue = function () {
  98. var queue = this._queue;
  99. var limit = this._limit;
  100. var values = this._values;
  101. while (queue.length > 0 && this._inFlight < limit) {
  102. if (this._isResolved()) return;
  103. var index = queue.pop();
  104. this._promiseFulfilled(values[index], index);
  105. }
  106. };
  107. MappingPromiseArray.prototype._filter = function (booleans, values) {
  108. var len = values.length;
  109. var ret = new Array(len);
  110. var j = 0;
  111. for (var i = 0; i < len; ++i) {
  112. if (booleans[i]) ret[j++] = values[i];
  113. }
  114. ret.length = j;
  115. this._resolve(ret);
  116. };
  117. MappingPromiseArray.prototype.preservedValues = function () {
  118. return this._preservedValues;
  119. };
  120. function map(promises, fn, options, _filter) {
  121. if (typeof fn !== "function") {
  122. return apiRejection("expecting a function but got " + util.classString(fn));
  123. }
  124. var limit = typeof options === "object" && options !== null
  125. ? options.concurrency
  126. : 0;
  127. limit = typeof limit === "number" &&
  128. isFinite(limit) && limit >= 1 ? limit : 0;
  129. return new MappingPromiseArray(promises, fn, limit, _filter).promise();
  130. }
  131. Promise.prototype.map = function (fn, options) {
  132. return map(this, fn, options, null);
  133. };
  134. Promise.map = function (promises, fn, options, _filter) {
  135. return map(promises, fn, options, _filter);
  136. };
  137. };