Spaces:
Sleeping
Sleeping
| ; | |
| module.exports = function(Promise, | |
| PromiseArray, | |
| apiRejection, | |
| tryConvertToPromise, | |
| INTERNAL, | |
| debug) { | |
| var util = require("./util"); | |
| var tryCatch = util.tryCatch; | |
| function ReductionPromiseArray(promises, fn, initialValue, _each) { | |
| this.constructor$(promises); | |
| var context = Promise._getContext(); | |
| this._fn = util.contextBind(context, fn); | |
| if (initialValue !== undefined) { | |
| initialValue = Promise.resolve(initialValue); | |
| initialValue._attachCancellationCallback(this); | |
| } | |
| this._initialValue = initialValue; | |
| this._currentCancellable = null; | |
| if(_each === INTERNAL) { | |
| this._eachValues = Array(this._length); | |
| } else if (_each === 0) { | |
| this._eachValues = null; | |
| } else { | |
| this._eachValues = undefined; | |
| } | |
| this._promise._captureStackTrace(); | |
| this._init$(undefined, -5); | |
| } | |
| util.inherits(ReductionPromiseArray, PromiseArray); | |
| ReductionPromiseArray.prototype._gotAccum = function(accum) { | |
| if (this._eachValues !== undefined && | |
| this._eachValues !== null && | |
| accum !== INTERNAL) { | |
| this._eachValues.push(accum); | |
| } | |
| }; | |
| ReductionPromiseArray.prototype._eachComplete = function(value) { | |
| if (this._eachValues !== null) { | |
| this._eachValues.push(value); | |
| } | |
| return this._eachValues; | |
| }; | |
| ReductionPromiseArray.prototype._init = function() {}; | |
| ReductionPromiseArray.prototype._resolveEmptyArray = function() { | |
| this._resolve(this._eachValues !== undefined ? this._eachValues | |
| : this._initialValue); | |
| }; | |
| ReductionPromiseArray.prototype.shouldCopyValues = function () { | |
| return false; | |
| }; | |
| ReductionPromiseArray.prototype._resolve = function(value) { | |
| this._promise._resolveCallback(value); | |
| this._values = null; | |
| }; | |
| ReductionPromiseArray.prototype._resultCancelled = function(sender) { | |
| if (sender === this._initialValue) return this._cancel(); | |
| if (this._isResolved()) return; | |
| this._resultCancelled$(); | |
| if (this._currentCancellable instanceof Promise) { | |
| this._currentCancellable.cancel(); | |
| } | |
| if (this._initialValue instanceof Promise) { | |
| this._initialValue.cancel(); | |
| } | |
| }; | |
| ReductionPromiseArray.prototype._iterate = function (values) { | |
| this._values = values; | |
| var value; | |
| var i; | |
| var length = values.length; | |
| if (this._initialValue !== undefined) { | |
| value = this._initialValue; | |
| i = 0; | |
| } else { | |
| value = Promise.resolve(values[0]); | |
| i = 1; | |
| } | |
| this._currentCancellable = value; | |
| for (var j = i; j < length; ++j) { | |
| var maybePromise = values[j]; | |
| if (maybePromise instanceof Promise) { | |
| maybePromise.suppressUnhandledRejections(); | |
| } | |
| } | |
| if (!value.isRejected()) { | |
| for (; i < length; ++i) { | |
| var ctx = { | |
| accum: null, | |
| value: values[i], | |
| index: i, | |
| length: length, | |
| array: this | |
| }; | |
| value = value._then(gotAccum, undefined, undefined, ctx, undefined); | |
| if ((i & 127) === 0) { | |
| value._setNoAsyncGuarantee(); | |
| } | |
| } | |
| } | |
| if (this._eachValues !== undefined) { | |
| value = value | |
| ._then(this._eachComplete, undefined, undefined, this, undefined); | |
| } | |
| value._then(completed, completed, undefined, value, this); | |
| }; | |
| Promise.prototype.reduce = function (fn, initialValue) { | |
| return reduce(this, fn, initialValue, null); | |
| }; | |
| Promise.reduce = function (promises, fn, initialValue, _each) { | |
| return reduce(promises, fn, initialValue, _each); | |
| }; | |
| function completed(valueOrReason, array) { | |
| if (this.isFulfilled()) { | |
| array._resolve(valueOrReason); | |
| } else { | |
| array._reject(valueOrReason); | |
| } | |
| } | |
| function reduce(promises, fn, initialValue, _each) { | |
| if (typeof fn !== "function") { | |
| return apiRejection("expecting a function but got " + util.classString(fn)); | |
| } | |
| var array = new ReductionPromiseArray(promises, fn, initialValue, _each); | |
| return array.promise(); | |
| } | |
| function gotAccum(accum) { | |
| this.accum = accum; | |
| this.array._gotAccum(accum); | |
| var value = tryConvertToPromise(this.value, this.array._promise); | |
| if (value instanceof Promise) { | |
| this.array._currentCancellable = value; | |
| return value._then(gotValue, undefined, undefined, this, undefined); | |
| } else { | |
| return gotValue.call(this, value); | |
| } | |
| } | |
| function gotValue(value) { | |
| var array = this.array; | |
| var promise = array._promise; | |
| var fn = tryCatch(array._fn); | |
| promise._pushContext(); | |
| var ret; | |
| if (array._eachValues !== undefined) { | |
| ret = fn.call(promise._boundValue(), value, this.index, this.length); | |
| } else { | |
| ret = fn.call(promise._boundValue(), | |
| this.accum, value, this.index, this.length); | |
| } | |
| if (ret instanceof Promise) { | |
| array._currentCancellable = ret; | |
| } | |
| var promiseCreated = promise._popContext(); | |
| debug.checkForgottenReturns( | |
| ret, | |
| promiseCreated, | |
| array._eachValues !== undefined ? "Promise.each" : "Promise.reduce", | |
| promise | |
| ); | |
| return ret; | |
| } | |
| }; | |