1"use strict"; 2module.exports = function(Promise, 3 PromiseArray, 4 apiRejection, 5 tryConvertToPromise, 6 INTERNAL, 7 debug) { 8var getDomain = Promise._getDomain; 9var util = require("./util"); 10var tryCatch = util.tryCatch; 11 12function ReductionPromiseArray(promises, fn, initialValue, _each) { 13 this.constructor$(promises); 14 var domain = getDomain(); 15 this._fn = domain === null ? fn : util.domainBind(domain, fn); 16 if (initialValue !== undefined) { 17 initialValue = Promise.resolve(initialValue); 18 initialValue._attachCancellationCallback(this); 19 } 20 this._initialValue = initialValue; 21 this._currentCancellable = null; 22 if(_each === INTERNAL) { 23 this._eachValues = Array(this._length); 24 } else if (_each === 0) { 25 this._eachValues = null; 26 } else { 27 this._eachValues = undefined; 28 } 29 this._promise._captureStackTrace(); 30 this._init$(undefined, -5); 31} 32util.inherits(ReductionPromiseArray, PromiseArray); 33 34ReductionPromiseArray.prototype._gotAccum = function(accum) { 35 if (this._eachValues !== undefined && 36 this._eachValues !== null && 37 accum !== INTERNAL) { 38 this._eachValues.push(accum); 39 } 40}; 41 42ReductionPromiseArray.prototype._eachComplete = function(value) { 43 if (this._eachValues !== null) { 44 this._eachValues.push(value); 45 } 46 return this._eachValues; 47}; 48 49ReductionPromiseArray.prototype._init = function() {}; 50 51ReductionPromiseArray.prototype._resolveEmptyArray = function() { 52 this._resolve(this._eachValues !== undefined ? this._eachValues 53 : this._initialValue); 54}; 55 56ReductionPromiseArray.prototype.shouldCopyValues = function () { 57 return false; 58}; 59 60ReductionPromiseArray.prototype._resolve = function(value) { 61 this._promise._resolveCallback(value); 62 this._values = null; 63}; 64 65ReductionPromiseArray.prototype._resultCancelled = function(sender) { 66 if (sender === this._initialValue) return this._cancel(); 67 if (this._isResolved()) return; 68 this._resultCancelled$(); 69 if (this._currentCancellable instanceof Promise) { 70 this._currentCancellable.cancel(); 71 } 72 if (this._initialValue instanceof Promise) { 73 this._initialValue.cancel(); 74 } 75}; 76 77ReductionPromiseArray.prototype._iterate = function (values) { 78 this._values = values; 79 var value; 80 var i; 81 var length = values.length; 82 if (this._initialValue !== undefined) { 83 value = this._initialValue; 84 i = 0; 85 } else { 86 value = Promise.resolve(values[0]); 87 i = 1; 88 } 89 90 this._currentCancellable = value; 91 92 if (!value.isRejected()) { 93 for (; i < length; ++i) { 94 var ctx = { 95 accum: null, 96 value: values[i], 97 index: i, 98 length: length, 99 array: this 100 }; 101 value = value._then(gotAccum, undefined, undefined, ctx, undefined); 102 } 103 } 104 105 if (this._eachValues !== undefined) { 106 value = value 107 ._then(this._eachComplete, undefined, undefined, this, undefined); 108 } 109 value._then(completed, completed, undefined, value, this); 110}; 111 112Promise.prototype.reduce = function (fn, initialValue) { 113 return reduce(this, fn, initialValue, null); 114}; 115 116Promise.reduce = function (promises, fn, initialValue, _each) { 117 return reduce(promises, fn, initialValue, _each); 118}; 119 120function completed(valueOrReason, array) { 121 if (this.isFulfilled()) { 122 array._resolve(valueOrReason); 123 } else { 124 array._reject(valueOrReason); 125 } 126} 127 128function reduce(promises, fn, initialValue, _each) { 129 if (typeof fn !== "function") { 130 return apiRejection("expecting a function but got " + util.classString(fn)); 131 } 132 var array = new ReductionPromiseArray(promises, fn, initialValue, _each); 133 return array.promise(); 134} 135 136function gotAccum(accum) { 137 this.accum = accum; 138 this.array._gotAccum(accum); 139 var value = tryConvertToPromise(this.value, this.array._promise); 140 if (value instanceof Promise) { 141 this.array._currentCancellable = value; 142 return value._then(gotValue, undefined, undefined, this, undefined); 143 } else { 144 return gotValue.call(this, value); 145 } 146} 147 148function gotValue(value) { 149 var array = this.array; 150 var promise = array._promise; 151 var fn = tryCatch(array._fn); 152 promise._pushContext(); 153 var ret; 154 if (array._eachValues !== undefined) { 155 ret = fn.call(promise._boundValue(), value, this.index, this.length); 156 } else { 157 ret = fn.call(promise._boundValue(), 158 this.accum, value, this.index, this.length); 159 } 160 if (ret instanceof Promise) { 161 array._currentCancellable = ret; 162 } 163 var promiseCreated = promise._popContext(); 164 debug.checkForgottenReturns( 165 ret, 166 promiseCreated, 167 array._eachValues !== undefined ? "Promise.each" : "Promise.reduce", 168 promise 169 ); 170 return ret; 171} 172}; 173