Как выполнить prom.all для массива массива promises?

Я пытаюсь запустить массив функций параллельно, и когда все заканчивается, я хочу работать над этим результатом. Я использую promises. Теперь я могу поместить все функции в массив и сделать Promise.all(массив функций) Но у меня есть массив вроде

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

где каждое обещание является обещаемой функцией. В ссылочном документе Promise указано, что параметр в Promise.all должен быть итерируемым объектом, а мой массив - итерируемым. Но это не работает для меня. Я думаю, что он выполняет [обещание1, обещание2] как обещание, но не индивидуальное обещание.

Может кто-нибудь, пожалуйста, помогите мне, как я могу это достичь или есть лучший способ?

Ответ 1

Вам также необходимо вызвать Promise.all для каждого элемента массива:

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

Или напрямую:

// 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)))

Таким образом, внешний Promise.all получает сгруппированные обещания в другом 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

Вы можете просто использовать Promise.all для всех внутренних массивов, а затем для внешнего массива, чтобы получить обещание для массива массивов:

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

Обратите внимание, что Promise.all принимает массив promises, а не массив функций, возвращающих обещание.

Ответ 3

Другим вариантом является сглаживание массива массивов в один массив, который можно использовать непосредственно Promise.all(). Прямо из примера в MDN, вы можете сделать это, как это, используя .reduce() и .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
});

Это решение позволяет исходному массиву promises содержать либо индивидуальные promises, либо массивы promises или любую комбинацию из двух. Он гибкий таким образом и дает результаты в одном сплющенном массиве результатов, которые находятся в том же порядке, что и исходный promises, но сплющиваются в один массив. Поскольку Promise.all() требует, чтобы вы передавали ему массив, другие представленные здесь решения требуют, чтобы вход был строгим массивом массивов - этот массив не может иметь простой promises в нем только массивы promises. Это решение является более гибким и будет принимать любой тип ввода.

Например, это будет прекрасно работать, если вход будет таким:

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

См. рабочую демонстрацию: https://jsfiddle.net/jfriend00/dLsktyyn/


Или вам может показаться полезным использовать функцию flatten() для других целей:

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

Если у вас есть фиксированное количество подмассивов, я рекомендую использовать это простое решение:

const balancePromises = [...];
const symbolPromises = [...];

const [balances, symbols] = await Promise.all([
    Promise.all(balancePromises),
    Promise.all(symbolPromises)
]);

Несколько обещаний также можно распараллелить следующим образом:

const [
    balances,
    debt,
    name,
] = await Promise.all([
    this.contract.getBalanceOf(user),
    this.contract.getDebtOf(user),
    this.contract.getNameOf(user),
]);

Ответ 5

Вы можете использовать этот подход:

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
});