| "use strict"; |
| module.exports = function(Promise, |
| PromiseArray, |
| apiRejection, |
| tryConvertToPromise, |
| INTERNAL, |
| debug) { |
| var util = require("./util"); |
| var tryCatch = util.tryCatch; |
| var errorObj = util.errorObj; |
| var async = Promise._async; |
| |
| function MappingPromiseArray(promises, fn, limit, _filter) { |
| this.constructor$(promises); |
| this._promise._captureStackTrace(); |
| var context = Promise._getContext(); |
| this._callback = util.contextBind(context, fn); |
| this._preservedValues = _filter === INTERNAL |
| ? new Array(this.length()) |
| : null; |
| this._limit = limit; |
| this._inFlight = 0; |
| this._queue = []; |
| async.invoke(this._asyncInit, this, undefined); |
| if (util.isArray(promises)) { |
| for (var i = 0; i < promises.length; ++i) { |
| var maybePromise = promises[i]; |
| if (maybePromise instanceof Promise) { |
| maybePromise.suppressUnhandledRejections(); |
| } |
| } |
| } |
| } |
| util.inherits(MappingPromiseArray, PromiseArray); |
| |
| MappingPromiseArray.prototype._asyncInit = function() { |
| this._init$(undefined, -2); |
| }; |
| |
| MappingPromiseArray.prototype._init = function () {}; |
| |
| MappingPromiseArray.prototype._promiseFulfilled = function (value, index) { |
| var values = this._values; |
| var length = this.length(); |
| var preservedValues = this._preservedValues; |
| var limit = this._limit; |
| |
| if (index < 0) { |
| index = (index * -1) - 1; |
| values[index] = value; |
| if (limit >= 1) { |
| this._inFlight--; |
| this._drainQueue(); |
| if (this._isResolved()) return true; |
| } |
| } else { |
| if (limit >= 1 && this._inFlight >= limit) { |
| values[index] = value; |
| this._queue.push(index); |
| return false; |
| } |
| if (preservedValues !== null) preservedValues[index] = value; |
| |
| var promise = this._promise; |
| var callback = this._callback; |
| var receiver = promise._boundValue(); |
| promise._pushContext(); |
| var ret = tryCatch(callback).call(receiver, value, index, length); |
| var promiseCreated = promise._popContext(); |
| debug.checkForgottenReturns( |
| ret, |
| promiseCreated, |
| preservedValues !== null ? "Promise.filter" : "Promise.map", |
| promise |
| ); |
| if (ret === errorObj) { |
| this._reject(ret.e); |
| return true; |
| } |
| |
| var maybePromise = tryConvertToPromise(ret, this._promise); |
| if (maybePromise instanceof Promise) { |
| maybePromise = maybePromise._target(); |
| var bitField = maybePromise._bitField; |
| ; |
| if (((bitField & 50397184) === 0)) { |
| if (limit >= 1) this._inFlight++; |
| values[index] = maybePromise; |
| maybePromise._proxy(this, (index + 1) * -1); |
| return false; |
| } else if (((bitField & 33554432) !== 0)) { |
| ret = maybePromise._value(); |
| } else if (((bitField & 16777216) !== 0)) { |
| this._reject(maybePromise._reason()); |
| return true; |
| } else { |
| this._cancel(); |
| return true; |
| } |
| } |
| values[index] = ret; |
| } |
| var totalResolved = ++this._totalResolved; |
| if (totalResolved >= length) { |
| if (preservedValues !== null) { |
| this._filter(values, preservedValues); |
| } else { |
| this._resolve(values); |
| } |
| return true; |
| } |
| return false; |
| }; |
| |
| MappingPromiseArray.prototype._drainQueue = function () { |
| var queue = this._queue; |
| var limit = this._limit; |
| var values = this._values; |
| while (queue.length > 0 && this._inFlight < limit) { |
| if (this._isResolved()) return; |
| var index = queue.pop(); |
| this._promiseFulfilled(values[index], index); |
| } |
| }; |
| |
| MappingPromiseArray.prototype._filter = function (booleans, values) { |
| var len = values.length; |
| var ret = new Array(len); |
| var j = 0; |
| for (var i = 0; i < len; ++i) { |
| if (booleans[i]) ret[j++] = values[i]; |
| } |
| ret.length = j; |
| this._resolve(ret); |
| }; |
| |
| MappingPromiseArray.prototype.preservedValues = function () { |
| return this._preservedValues; |
| }; |
| |
| function map(promises, fn, options, _filter) { |
| if (typeof fn !== "function") { |
| return apiRejection("expecting a function but got " + util.classString(fn)); |
| } |
| |
| var limit = 0; |
| if (options !== undefined) { |
| if (typeof options === "object" && options !== null) { |
| if (typeof options.concurrency !== "number") { |
| return Promise.reject( |
| new TypeError("'concurrency' must be a number but it is " + |
| util.classString(options.concurrency))); |
| } |
| limit = options.concurrency; |
| } else { |
| return Promise.reject(new TypeError( |
| "options argument must be an object but it is " + |
| util.classString(options))); |
| } |
| } |
| limit = typeof limit === "number" && |
| isFinite(limit) && limit >= 1 ? limit : 0; |
| return new MappingPromiseArray(promises, fn, limit, _filter).promise(); |
| } |
| |
| Promise.prototype.map = function (fn, options) { |
| return map(this, fn, options, null); |
| }; |
| |
| Promise.map = function (promises, fn, options, _filter) { |
| return map(promises, fn, options, _filter); |
| }; |
| |
| |
| }; |