2 module.exports = function(Promise,
7 var getDomain = Promise._getDomain;
8 var async = require("./async.js");
9 var util = require("./util.js");
10 var tryCatch = util.tryCatch;
11 var errorObj = util.errorObj;
12 function ReductionPromiseArray(promises, fn, accum, _each) {
13 this.constructor$(promises);
14 this._promise._captureStackTrace();
15 this._preservedValues = _each === INTERNAL ? [] : null;
16 this._zerothIsAccum = (accum === undefined);
17 this._gotAccum = false;
18 this._reducingIndex = (this._zerothIsAccum ? 1 : 0);
19 this._valuesPhase = undefined;
20 var maybePromise = tryConvertToPromise(accum, this._promise);
22 var isPromise = maybePromise instanceof Promise;
24 maybePromise = maybePromise._target();
25 if (maybePromise._isPending()) {
26 maybePromise._proxyPromiseArray(this, -1);
27 } else if (maybePromise._isFulfilled()) {
28 accum = maybePromise._value();
29 this._gotAccum = true;
31 this._reject(maybePromise._reason());
35 if (!(isPromise || this._zerothIsAccum)) this._gotAccum = true;
36 var domain = getDomain();
37 this._callback = domain === null ? fn : domain.bind(fn);
39 if (!rejected) async.invoke(init, this, undefined);
42 this._init$(undefined, -5);
44 util.inherits(ReductionPromiseArray, PromiseArray);
46 ReductionPromiseArray.prototype._init = function () {};
48 ReductionPromiseArray.prototype._resolveEmptyArray = function () {
49 if (this._gotAccum || this._zerothIsAccum) {
50 this._resolve(this._preservedValues !== null
55 ReductionPromiseArray.prototype._promiseFulfilled = function (value, index) {
56 var values = this._values;
57 values[index] = value;
58 var length = this.length();
59 var preservedValues = this._preservedValues;
60 var isEach = preservedValues !== null;
61 var gotAccum = this._gotAccum;
62 var valuesPhase = this._valuesPhase;
65 valuesPhase = this._valuesPhase = new Array(length);
66 for (valuesPhaseIndex=0; valuesPhaseIndex<length; ++valuesPhaseIndex) {
67 valuesPhase[valuesPhaseIndex] = 0;
70 valuesPhaseIndex = valuesPhase[index];
72 if (index === 0 && this._zerothIsAccum) {
74 this._gotAccum = gotAccum = true;
75 valuesPhase[index] = ((valuesPhaseIndex === 0)
77 } else if (index === -1) {
79 this._gotAccum = gotAccum = true;
81 if (valuesPhaseIndex === 0) {
82 valuesPhase[index] = 1;
84 valuesPhase[index] = 2;
88 if (!gotAccum) return;
90 var callback = this._callback;
91 var receiver = this._promise._boundValue();
94 for (var i = this._reducingIndex; i < length; ++i) {
95 valuesPhaseIndex = valuesPhase[i];
96 if (valuesPhaseIndex === 2) {
97 this._reducingIndex = i + 1;
100 if (valuesPhaseIndex !== 1) return;
102 this._promise._pushContext();
104 preservedValues.push(value);
105 ret = tryCatch(callback).call(receiver, value, i, length);
108 ret = tryCatch(callback)
109 .call(receiver, this._accum, value, i, length);
111 this._promise._popContext();
113 if (ret === errorObj) return this._reject(ret.e);
115 var maybePromise = tryConvertToPromise(ret, this._promise);
116 if (maybePromise instanceof Promise) {
117 maybePromise = maybePromise._target();
118 if (maybePromise._isPending()) {
120 return maybePromise._proxyPromiseArray(this, i);
121 } else if (maybePromise._isFulfilled()) {
122 ret = maybePromise._value();
124 return this._reject(maybePromise._reason());
128 this._reducingIndex = i + 1;
132 this._resolve(isEach ? preservedValues : this._accum);
135 function reduce(promises, fn, initialValue, _each) {
136 if (typeof fn !== "function") return apiRejection("fn must be a function\u000a\u000a See http://goo.gl/916lJJ\u000a");
137 var array = new ReductionPromiseArray(promises, fn, initialValue, _each);
138 return array.promise();
141 Promise.prototype.reduce = function (fn, initialValue) {
142 return reduce(this, fn, initialValue, null);
145 Promise.reduce = function (promises, fn, initialValue, _each) {
146 return reduce(promises, fn, initialValue, _each);