2 module.exports = function(Promise,
7 var getDomain = Promise._getDomain;
8 var async = require("./async.js");
9 var util = require("./util.js");
10 var tryCatch = util.tryCatch;
11 var errorObj = util.errorObj;
15 function MappingPromiseArray(promises, fn, limit, _filter) {
16 this.constructor$(promises);
17 this._promise._captureStackTrace();
18 var domain = getDomain();
19 this._callback = domain === null ? fn : domain.bind(fn);
20 this._preservedValues = _filter === INTERNAL
21 ? new Array(this.length())
25 this._queue = limit >= 1 ? [] : EMPTY_ARRAY;
26 async.invoke(init, this, undefined);
28 util.inherits(MappingPromiseArray, PromiseArray);
29 function init() {this._init$(undefined, -2);}
31 MappingPromiseArray.prototype._init = function () {};
33 MappingPromiseArray.prototype._promiseFulfilled = function (value, index) {
34 var values = this._values;
35 var length = this.length();
36 var preservedValues = this._preservedValues;
37 var limit = this._limit;
38 if (values[index] === PENDING) {
39 values[index] = value;
43 if (this._isResolved()) return;
46 if (limit >= 1 && this._inFlight >= limit) {
47 values[index] = value;
48 this._queue.push(index);
51 if (preservedValues !== null) preservedValues[index] = value;
53 var callback = this._callback;
54 var receiver = this._promise._boundValue();
55 this._promise._pushContext();
56 var ret = tryCatch(callback).call(receiver, value, index, length);
57 this._promise._popContext();
58 if (ret === errorObj) return this._reject(ret.e);
60 var maybePromise = tryConvertToPromise(ret, this._promise);
61 if (maybePromise instanceof Promise) {
62 maybePromise = maybePromise._target();
63 if (maybePromise._isPending()) {
64 if (limit >= 1) this._inFlight++;
65 values[index] = PENDING;
66 return maybePromise._proxyPromiseArray(this, index);
67 } else if (maybePromise._isFulfilled()) {
68 ret = maybePromise._value();
70 return this._reject(maybePromise._reason());
75 var totalResolved = ++this._totalResolved;
76 if (totalResolved >= length) {
77 if (preservedValues !== null) {
78 this._filter(values, preservedValues);
80 this._resolve(values);
86 MappingPromiseArray.prototype._drainQueue = function () {
87 var queue = this._queue;
88 var limit = this._limit;
89 var values = this._values;
90 while (queue.length > 0 && this._inFlight < limit) {
91 if (this._isResolved()) return;
92 var index = queue.pop();
93 this._promiseFulfilled(values[index], index);
97 MappingPromiseArray.prototype._filter = function (booleans, values) {
98 var len = values.length;
99 var ret = new Array(len);
101 for (var i = 0; i < len; ++i) {
102 if (booleans[i]) ret[j++] = values[i];
108 MappingPromiseArray.prototype.preservedValues = function () {
109 return this._preservedValues;
112 function map(promises, fn, options, _filter) {
113 var limit = typeof options === "object" && options !== null
114 ? options.concurrency
116 limit = typeof limit === "number" &&
117 isFinite(limit) && limit >= 1 ? limit : 0;
118 return new MappingPromiseArray(promises, fn, limit, _filter);
121 Promise.prototype.map = function (fn, options) {
122 if (typeof fn !== "function") return apiRejection("fn must be a function\u000a\u000a See http://goo.gl/916lJJ\u000a");
124 return map(this, fn, options, null).promise();
127 Promise.map = function (promises, fn, options, _filter) {
128 if (typeof fn !== "function") return apiRejection("fn must be a function\u000a\u000a See http://goo.gl/916lJJ\u000a");
129 return map(promises, fn, options, _filter).promise();