Ожидание Promises для разрешения внутри массива

С Массив Promises как подождать, пока все они не будут решены, прежде чем продолжить?

Ниже приведен пример реализации, где task_2 запускает его отклонение до того, как task_1 может запускаться.

const $output = $$('output')

const config = {
  task_1: [
    val => new Promise((resolve, reject) => setTimeout(() => reject('Awaited error'), 2000)),
    val => new Promise((resolve, reject) => resolve(val))
  ],
  task_2: [
    val => new Promise((resolve, reject) => resolve(val)),
    val => new Promise((resolve, reject) => reject('An error')),
  ]
}

taskRunner({
    task_1: 'task parameters',
    task_2: 'task parameters'
  })
  .then(res => $output.text(res).fadeIn())
  .catch(err => $output.text(err).fadeIn())

function taskRunner(tasks) {
  return new Promise((resolve, reject) => {
    let arr = []
    for (const task in tasks) {
      if (!config.hasOwnProperty(task)) return reject(`${task} has no tasks`)
      arr.push(config[task].map((cb => cb(tasks[task]))))
    }

    const toRun = arr.reduce((a, b) => a.concat(b))
    Promise.all(toRun)
      .then(res => resolve(res))
      .catch(err => reject(err))
  })
}

function $$(data) {
  return $('[data-' + data + ']')
}
html, body { margin: 0; padding: 0 }
div.output {
  font-family: 'Courier', monospace;
  color: #383838;
  margin: 15px;
  padding: 15px 20px;
  background: #fafafa;
  border-radius: 3px;
  border-bottom: 1px solid #dadada;
}
.js-hide { display: none }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="output js-hide" data-output></div>

Ответ 1

Если я правильно понял ваш вопрос из вашего комментария

На самом деле это просто пример, мне любопытно, как вы дождались, когда массив Promises до разрешить/отклонить, прежде чем продолжить. Например, у вас может быть массив из Promises, который делает HTTP-вызовы, в случае ошибки вы хотите вывести все ошибки, а не самые последние.

вы хотите дождаться, пока все Promises не будут разрешены или отклонены, а затем продолжайте.

Promise.all() отклонит, если какой-либо из данных Promises в массиве отклонен, таким образом, это не является альтернативой для вашего в этом случае.

В jQuery есть функция .always(), которая работает так, и если вы должны использовать BlueBird, вы можете использовать .reflect() для проверки Promises Promise.all(). В ES6 нет текущей функции, которая может это сделать.

Заимствование из ответа на этот вопрос ES6 обещал улаживать обратный вызов?, вы можете реализовать свою собственную версию .always()/.finally()/.allSettled() как это

Promise.prototype.finally = function(cb) {
    const res = () => this
    return this.then(value =>
        Promise.resolve(cb({state:"fulfilled", value})).then(res)
    , reason =>
        Promise.resolve(cb({state:"rejected", reason})).then(res)
    );
};

Ответ 2

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

В качестве примера;

function handleRejectedPromises(p){
  return new Promise((resolve,reject) => p.then(v => resolve({status: "resolved", value: v}))
                                          .catch(x => resolve({status: "rejected", reason: x})));
}
var ps = [Promise.resolve(42), Promise.reject(37), Promise.resolve(23), Promise.resolve(11)];

Promise.all(ps.map(p => handleRejectedPromises(p)))
       .then(ra => ra.forEach(r => console.log(r)));