123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- "use strict";
- module.exports = function(Promise,
- PromiseArray,
- apiRejection,
- tryConvertToPromise,
- INTERNAL) {
- var async = require("./async.js");
- var util = require("./util.js");
- var tryCatch = util.tryCatch;
- var errorObj = util.errorObj;
- function ReductionPromiseArray(promises, fn, accum, _each) {
- this.constructor$(promises);
- this._promise._captureStackTrace();
- this._preservedValues = _each === INTERNAL ? [] : null;
- this._zerothIsAccum = (accum === undefined);
- this._gotAccum = false;
- this._reducingIndex = (this._zerothIsAccum ? 1 : 0);
- this._valuesPhase = undefined;
- var maybePromise = tryConvertToPromise(accum, this._promise);
- var rejected = false;
- var isPromise = maybePromise instanceof Promise;
- if (isPromise) {
- maybePromise = maybePromise._target();
- if (maybePromise._isPending()) {
- maybePromise._proxyPromiseArray(this, -1);
- } else if (maybePromise._isFulfilled()) {
- accum = maybePromise._value();
- this._gotAccum = true;
- } else {
- this._reject(maybePromise._reason());
- rejected = true;
- }
- }
- if (!(isPromise || this._zerothIsAccum)) this._gotAccum = true;
- this._callback = fn;
- this._accum = accum;
- if (!rejected) async.invoke(init, this, undefined);
- }
- function init() {
- this._init$(undefined, -5);
- }
- util.inherits(ReductionPromiseArray, PromiseArray);
- ReductionPromiseArray.prototype._init = function () {};
- ReductionPromiseArray.prototype._resolveEmptyArray = function () {
- if (this._gotAccum || this._zerothIsAccum) {
- this._resolve(this._preservedValues !== null
- ? [] : this._accum);
- }
- };
- ReductionPromiseArray.prototype._promiseFulfilled = function (value, index) {
- var values = this._values;
- values[index] = value;
- var length = this.length();
- var preservedValues = this._preservedValues;
- var isEach = preservedValues !== null;
- var gotAccum = this._gotAccum;
- var valuesPhase = this._valuesPhase;
- var valuesPhaseIndex;
- if (!valuesPhase) {
- valuesPhase = this._valuesPhase = new Array(length);
- for (valuesPhaseIndex=0; valuesPhaseIndex<length; ++valuesPhaseIndex) {
- valuesPhase[valuesPhaseIndex] = 0;
- }
- }
- valuesPhaseIndex = valuesPhase[index];
- if (index === 0 && this._zerothIsAccum) {
- this._accum = value;
- this._gotAccum = gotAccum = true;
- valuesPhase[index] = ((valuesPhaseIndex === 0)
- ? 1 : 2);
- } else if (index === -1) {
- this._accum = value;
- this._gotAccum = gotAccum = true;
- } else {
- if (valuesPhaseIndex === 0) {
- valuesPhase[index] = 1;
- } else {
- valuesPhase[index] = 2;
- this._accum = value;
- }
- }
- if (!gotAccum) return;
- var callback = this._callback;
- var receiver = this._promise._boundTo;
- var ret;
- for (var i = this._reducingIndex; i < length; ++i) {
- valuesPhaseIndex = valuesPhase[i];
- if (valuesPhaseIndex === 2) {
- this._reducingIndex = i + 1;
- continue;
- }
- if (valuesPhaseIndex !== 1) return;
- value = values[i];
- this._promise._pushContext();
- if (isEach) {
- preservedValues.push(value);
- ret = tryCatch(callback).call(receiver, value, i, length);
- }
- else {
- ret = tryCatch(callback)
- .call(receiver, this._accum, value, i, length);
- }
- this._promise._popContext();
- if (ret === errorObj) return this._reject(ret.e);
- var maybePromise = tryConvertToPromise(ret, this._promise);
- if (maybePromise instanceof Promise) {
- maybePromise = maybePromise._target();
- if (maybePromise._isPending()) {
- valuesPhase[i] = 4;
- return maybePromise._proxyPromiseArray(this, i);
- } else if (maybePromise._isFulfilled()) {
- ret = maybePromise._value();
- } else {
- return this._reject(maybePromise._reason());
- }
- }
- this._reducingIndex = i + 1;
- this._accum = ret;
- }
- this._resolve(isEach ? preservedValues : this._accum);
- };
- function reduce(promises, fn, initialValue, _each) {
- if (typeof fn !== "function") return apiRejection("fn must be a function\u000a\u000a See http://goo.gl/916lJJ\u000a");
- var array = new ReductionPromiseArray(promises, fn, initialValue, _each);
- return array.promise();
- }
- 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);
- };
- };
|