How to do promise.all for array of array of promis

2019-02-12 11:10发布

问题:

I am trying to run array of functions parallel and when everybody finishes I want work on that result. I am using promises. Now, I can put all functions in an array and can do Promise.all(array of functions) But I have array like

[[promise1, promise2], [promise3,promise4], [promise5,promise6]],

where each promise is promisified function. Promise reference document says parameter in Promise.all should be an iterable object and my array is iterable. But it is not working for me. I think It is executing [promise1, promise2] as a promise but not individual promise.

Can anybody please help me how I can achieve it or is there any better way ?

回答1:

You need to also call Promise.all for each array item:

const promise4all = Promise.all(
   promiseArray.map(function(innerPromiseArray) {
        return Promise.all(innerPromiseArray);
   })
);

Or directly:

// Fix: Promise.all.bind is required because it seems like Promise.all
// implementation relies on "this"
const promise4All = Promise.all(promiseArray.map(Promise.all.bind(Promise)))
// or
// const promise4All = Promise.all(promiseArray.map(p => Promise.all(p)))

This way the outer Promise.all gets the grouped promises in other Promise.all:

promise4all.then(function(promiseGroupResult) {
  // promiseGroupResult is the actual result of each promise group
  // and you'll be able to get each result this way: promiseGroupResult.somePropertyName
});


回答2:

You can just use Promise.all on all inner arrays, then on the outer array, to get a promise for the array of arrays:

Promise.all(promiseArrArr.map(Promise.all, Promise)).then(arrArr => …)

Notice that Promise.all takes an array of promises, not an array of promise-returning functions.



回答3:

One other option is to flatten your array of arrays into a single array that you can then use Promise.all() on directly. Straight from an example on MDN, you can do that like this using .reduce() and .concat():

var promises = [[promise1, promise2], [promise3,promise4], [promise5,promise6]];

Promise.all(promises.reduce(function(a, b) { return a.concat(b); }, []))
  .then(function(results) {
    // all done here
    // results are in a flattened array
});

This solution allows the original promises array to contain either individual promises or arrays of promises or any combination of the two. It's flexible in that way and it provides the results in a single flattened array of results that are in the same order as the original promises, but are flattened into a single array. Because Promise.all() requires that you pass it an array, the other solutions presented here require the input to be a strict array of arrays - that array cannot have any plain promises in it only arrays of promises. This solution is more flexible in that way and will accept either type of input.

For example, this will work just fine if the input happens to be like this:

var promises = [promise1, promise2, [promise3, promise4], [promise5, promise6]];

See working demo: https://jsfiddle.net/jfriend00/dLsktyyn/


Or you might find it useful to have the flatten() function lying around for other uses:

function flatten(arr) {
    return arr.reduce(function(a, b) { return a.concat(b); }, []);
}

var promises = [[promise1, promise2], [promise3,promise4], [promise5,promise6]];

Promise.all(flatten(promises)).then(function(results) {
    // all done here
});    


回答4:

You can use this approach:

var promisesArray = [
    [promise1, promise2],
    [promise3,promise4],
    [promise5,promise6]
].reduce(function (arr, item) {
    item.forEach(function (promise) {
       arr.push(promise);
    });
    return arr;
}, []);
Promise.all(promisesArray).then(function () {
    // code
});