|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
"use strict"; |
|
module.exports = function( |
|
Promise, Promise$_CreatePromiseArray, |
|
PromiseArray, apiRejection, INTERNAL) { |
|
|
|
var ASSERT = require("./assert.js"); |
|
|
|
function Reduction(callback, index, accum, items, receiver) { |
|
this.promise = new Promise(INTERNAL); |
|
this.index = index; |
|
this.length = items.length; |
|
this.items = items; |
|
this.callback = callback; |
|
this.receiver = receiver; |
|
this.accum = accum; |
|
} |
|
|
|
Reduction.prototype.reject = function Reduction$reject(e) { |
|
this.promise._reject(e); |
|
}; |
|
|
|
Reduction.prototype.fulfill = function Reduction$fulfill(value, index) { |
|
this.accum = value; |
|
this.index = index + 1; |
|
this.iterate(); |
|
}; |
|
|
|
Reduction.prototype.iterate = function Reduction$iterate() { |
|
var i = this.index; |
|
var len = this.length; |
|
var items = this.items; |
|
var result = this.accum; |
|
var receiver = this.receiver; |
|
var callback = this.callback; |
|
var iterate = this.iterate; |
|
|
|
for(; i < len; ++i) { |
|
result = Promise._cast( |
|
callback.call( |
|
receiver, |
|
result, |
|
items[i], |
|
i, |
|
len |
|
), |
|
iterate, |
|
void 0 |
|
); |
|
|
|
if (result instanceof Promise) { |
|
result._then( |
|
this.fulfill, this.reject, void 0, this, i, iterate); |
|
return; |
|
} |
|
} |
|
this.promise._fulfill(result); |
|
}; |
|
|
|
function Promise$_reducer(fulfilleds, initialValue) { |
|
var fn = this; |
|
var receiver = void 0; |
|
if (typeof fn !== "function") { |
|
receiver = fn.receiver; |
|
fn = fn.fn; |
|
} |
|
var len = fulfilleds.length; |
|
var accum = void 0; |
|
var startIndex = 0; |
|
|
|
if (initialValue !== void 0) { |
|
accum = initialValue; |
|
startIndex = 0; |
|
} |
|
else { |
|
startIndex = 1; |
|
if (len > 0) accum = fulfilleds[0]; |
|
} |
|
var i = startIndex; |
|
|
|
if (i >= len) { |
|
return accum; |
|
} |
|
|
|
var reduction = new Reduction(fn, i, accum, fulfilleds, receiver); |
|
reduction.iterate(); |
|
return reduction.promise; |
|
} |
|
|
|
function Promise$_unpackReducer(fulfilleds) { |
|
var fn = this.fn; |
|
var initialValue = this.initialValue; |
|
return Promise$_reducer.call(fn, fulfilleds, initialValue); |
|
} |
|
|
|
function Promise$_slowReduce( |
|
promises, fn, initialValue, useBound, caller) { |
|
return initialValue._then(function callee(initialValue) { |
|
return Promise$_Reduce( |
|
promises, fn, initialValue, useBound, callee); |
|
}, void 0, void 0, void 0, void 0, caller); |
|
} |
|
|
|
function Promise$_Reduce(promises, fn, initialValue, useBound, caller) { |
|
if (typeof fn !== "function") { |
|
return apiRejection("fn must be a function"); |
|
} |
|
|
|
if (useBound === true && promises._isBound()) { |
|
fn = { |
|
fn: fn, |
|
receiver: promises._boundTo |
|
}; |
|
} |
|
|
|
if (initialValue !== void 0) { |
|
if (Promise.is(initialValue)) { |
|
if (initialValue.isFulfilled()) { |
|
initialValue = initialValue._settledValue; |
|
} |
|
else { |
|
return Promise$_slowReduce(promises, |
|
fn, initialValue, useBound, caller); |
|
} |
|
} |
|
|
|
return Promise$_CreatePromiseArray(promises, PromiseArray, caller, |
|
useBound === true && promises._isBound() |
|
? promises._boundTo |
|
: void 0) |
|
.promise() |
|
._then(Promise$_unpackReducer, void 0, void 0, { |
|
fn: fn, |
|
initialValue: initialValue |
|
}, void 0, Promise.reduce); |
|
} |
|
return Promise$_CreatePromiseArray(promises, PromiseArray, caller, |
|
useBound === true && promises._isBound() |
|
? promises._boundTo |
|
: void 0).promise() |
|
._then(Promise$_reducer, void 0, void 0, fn, void 0, caller); |
|
} |
|
|
|
|
|
Promise.reduce = function Promise$Reduce(promises, fn, initialValue) { |
|
return Promise$_Reduce(promises, fn, |
|
initialValue, false, Promise.reduce); |
|
}; |
|
|
|
Promise.prototype.reduce = function Promise$reduce(fn, initialValue) { |
|
return Promise$_Reduce(this, fn, initialValue, |
|
true, this.reduce); |
|
}; |
|
}; |
|
|