1f92dafacd685633994c82d5e293aa2057dd09dd
[aai/esr-gui.git] /
1 "use strict";
2 module.exports = function(Promise,
3                           PromiseArray,
4                           apiRejection,
5                           tryConvertToPromise,
6                           INTERNAL) {
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);
21     var rejected = false;
22     var isPromise = maybePromise instanceof Promise;
23     if (isPromise) {
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;
30         } else {
31             this._reject(maybePromise._reason());
32             rejected = true;
33         }
34     }
35     if (!(isPromise || this._zerothIsAccum)) this._gotAccum = true;
36     var domain = getDomain();
37     this._callback = domain === null ? fn : domain.bind(fn);
38     this._accum = accum;
39     if (!rejected) async.invoke(init, this, undefined);
40 }
41 function init() {
42     this._init$(undefined, -5);
43 }
44 util.inherits(ReductionPromiseArray, PromiseArray);
45
46 ReductionPromiseArray.prototype._init = function () {};
47
48 ReductionPromiseArray.prototype._resolveEmptyArray = function () {
49     if (this._gotAccum || this._zerothIsAccum) {
50         this._resolve(this._preservedValues !== null
51                         ? [] : this._accum);
52     }
53 };
54
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;
63     var valuesPhaseIndex;
64     if (!valuesPhase) {
65         valuesPhase = this._valuesPhase = new Array(length);
66         for (valuesPhaseIndex=0; valuesPhaseIndex<length; ++valuesPhaseIndex) {
67             valuesPhase[valuesPhaseIndex] = 0;
68         }
69     }
70     valuesPhaseIndex = valuesPhase[index];
71
72     if (index === 0 && this._zerothIsAccum) {
73         this._accum = value;
74         this._gotAccum = gotAccum = true;
75         valuesPhase[index] = ((valuesPhaseIndex === 0)
76             ? 1 : 2);
77     } else if (index === -1) {
78         this._accum = value;
79         this._gotAccum = gotAccum = true;
80     } else {
81         if (valuesPhaseIndex === 0) {
82             valuesPhase[index] = 1;
83         } else {
84             valuesPhase[index] = 2;
85             this._accum = value;
86         }
87     }
88     if (!gotAccum) return;
89
90     var callback = this._callback;
91     var receiver = this._promise._boundValue();
92     var ret;
93
94     for (var i = this._reducingIndex; i < length; ++i) {
95         valuesPhaseIndex = valuesPhase[i];
96         if (valuesPhaseIndex === 2) {
97             this._reducingIndex = i + 1;
98             continue;
99         }
100         if (valuesPhaseIndex !== 1) return;
101         value = values[i];
102         this._promise._pushContext();
103         if (isEach) {
104             preservedValues.push(value);
105             ret = tryCatch(callback).call(receiver, value, i, length);
106         }
107         else {
108             ret = tryCatch(callback)
109                 .call(receiver, this._accum, value, i, length);
110         }
111         this._promise._popContext();
112
113         if (ret === errorObj) return this._reject(ret.e);
114
115         var maybePromise = tryConvertToPromise(ret, this._promise);
116         if (maybePromise instanceof Promise) {
117             maybePromise = maybePromise._target();
118             if (maybePromise._isPending()) {
119                 valuesPhase[i] = 4;
120                 return maybePromise._proxyPromiseArray(this, i);
121             } else if (maybePromise._isFulfilled()) {
122                 ret = maybePromise._value();
123             } else {
124                 return this._reject(maybePromise._reason());
125             }
126         }
127
128         this._reducingIndex = i + 1;
129         this._accum = ret;
130     }
131
132     this._resolve(isEach ? preservedValues : this._accum);
133 };
134
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();
139 }
140
141 Promise.prototype.reduce = function (fn, initialValue) {
142     return reduce(this, fn, initialValue, null);
143 };
144
145 Promise.reduce = function (promises, fn, initialValue, _each) {
146     return reduce(promises, fn, initialValue, _each);
147 };
148 };