diff --git a/src/map.js b/src/map.js index dd7244e6d..506842ab9 100644 --- a/src/map.js +++ b/src/map.js @@ -23,14 +23,15 @@ function MappingPromiseArray(promises, fn, limit, _filter) { this._limit = limit; this._inFlight = 0; this._queue = []; - async.invoke(this._asyncInit, this, undefined); + this._asyncQueue = []; + this._init$(undefined, RESOLVE_ARRAY); + if (!this._isResolved() && this._asyncQueue.length > 0) { + async.invoke(this._drainAsyncQueue, this, this._asyncQueue); + } + this._asyncQueue = undefined; } util.inherits(MappingPromiseArray, PromiseArray); -MappingPromiseArray.prototype._asyncInit = function() { - this._init$(undefined, RESOLVE_ARRAY); -}; - // The following hack is required because the super constructor // might call promiseFulfilled before this.callback = fn is set // @@ -60,6 +61,12 @@ MappingPromiseArray.prototype._promiseFulfilled = function (value, index) { if (this._isResolved()) return true; } } else { + if (this._asyncQueue !== undefined) { + values[index] = value; + this._asyncQueue.push(index); + return false; + } + if (limit >= 1 && this._inFlight >= limit) { values[index] = value; this._queue.push(index); @@ -144,6 +151,16 @@ MappingPromiseArray.prototype._filter = function (booleans, values) { this._resolve(ret); }; +MappingPromiseArray.prototype._drainAsyncQueue = function (queue) { + var values = this._values; + var len = queue.length; + var index; + for (var i = 0; i < len && !this._isResolved(); ++i) { + index = queue[i]; + this._promiseFulfilled(values[index], index); + } +}; + MappingPromiseArray.prototype.preservedValues = function () { return this._preservedValues; }; diff --git a/test/mocha/map.js b/test/mocha/map.js index 2387290c3..ad00132e1 100644 --- a/test/mocha/map.js +++ b/test/mocha/map.js @@ -103,8 +103,13 @@ describe("Promise.map-test", function () { }); specify("should reject when input contains rejection", function() { - var input = [Promise.resolve(1), Promise.reject(2), Promise.resolve(3)]; - return Promise.map(input, mapper).then( + var input = [Promise.resolve(1), Promise.reject(2), Promise.reject(3)]; + var promise = Promise.map(input, mapper); + + assert(!input[1]._isRejectionUnhandled()); + assert(!input[2]._isRejectionUnhandled()); + + return promise.then( assert.fail, function(result) { assert(result === 2); @@ -232,8 +237,13 @@ describe("Promise.map-test with concurrency", function () { }); specify("should reject when input contains rejection with concurrency", function() { - var input = [Promise.resolve(1), Promise.reject(2), Promise.resolve(3)]; - return Promise.map(input, mapper, concurrency).then( + var input = [Promise.resolve(1), Promise.reject(2), Promise.reject(3)]; + var promise = Promise.map(input, mapper, concurrency); + + assert(!input[1]._isRejectionUnhandled()); + assert(!input[2]._isRejectionUnhandled()); + + return promise.then( assert.fail, function(result) { assert(result === 2);