You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
175 lines
5.5 KiB
175 lines
5.5 KiB
"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); |
|
}; |
|
|
|
|
|
};
|
|
|