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