Ожидание 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)));