Given this pattern
someArray.reduce(function(p, item) {
return p.then(function() {
return someFunction(item);
});
}, $.Deferred().resolve()).then(function() {
// all done here
// access accumulated fulfilled , rejected `Promise` values
}, function err() {
});
what approaches are possible to return accumulated values of fulfilled , rejected Promise
objects to .then(fulfilled)
as an array following call to .reduce()
?
function someFunction(index) {
console.log("someFunction called, index = " + index);
var $deferred = $.Deferred();
window.setTimeout(function() {
$deferred.resolve();
}, 2000);
return $deferred.promise();
}
var someArray = [1,2,3,4,5];
someArray.reduce(function(p, item) {
return p.then(function() {
return someFunction(item);
});
}, $.Deferred().resolve()).then(function(data) {
// all done here
console.log(data, arguments) // `undefined` , `[]`
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
There are multiple possible strategies depending upon the specifics of what you're trying to do: Here's one option:
Working demo: http://jsfiddle.net/jfriend00/d4q1aaa0/
FYI, the Bluebird Promise library (which is what I generally use) has
.mapSeries()
which is built for this pattern:Working demo: http://jsfiddle.net/jfriend00/7fm3wv7j/
One solution possible :
Next to the approach demonstrated by @jfriend00, where you resolve each promise with an array where you append the current to all previous results, you can also use an array of promises as is known from the parallel execution pattern with
Promise.all
and.map
.For this, you have to put all the promises you create within the
reduce
steps in an array. After that, you can callPromise.all
on this array to await all the results. The advantage of this approach is that your code only needs minimal adjustment, so that you can easily switch back and forth between a version that needs the results and one that does not.To collect the results of each step in an array, we use a variant of
reduce
that is known asscan
and does return an array (likemap
) instead of the latest result:The pattern now looks like
(For jQuery, substitute
Promise.resolve
by$.Deferred().resolve()
andPromise.all
by$.when.apply($, …)
)