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.
		
		
		
		
		
			
		
			
				
					184 lines
				
				5.2 KiB
			
		
		
			
		
	
	
					184 lines
				
				5.2 KiB
			| 
											3 years ago
										 | "use strict"; | ||
|  | 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; | ||
|  | } | ||
|  | }; |