Комментарии 33
В данном примере результов нет, так как delayedLog
просто выводил в консоль. Но если нужны то:
const results = await Promise.all(array.map(delayedLog););
try catch
.Я для этого писал функцию promiseResolveAll, но может быть, есть более хороший способ.
async function promiseResolveAll(promises){
if(promises.length === 0){
return [];
}
return new Promise(resolve => {
var results = [];
var processed = 0;
function onPromiseAnswer(type, i){
return value => {
results[i] = type ? {ok: true, value: value} : {ok: false, error: value};
if(++processed === promises.length){
resolve(results);
}
};
}
promises.forEach((promise, i) => {
promise.then(onPromiseAnswer(true, i)).catch(onPromiseAnswer(false, i));
});
});
}
const promises = [
Promise.resolve(1),
Promise.reject('something wrong'),
Promise.resolve(3),
];
function fail(error) {
return {ok: false, error};
};
function success(value) {
return {ok: true, value};
};
const results = await Promise.all(
promises.map(p => p.then(success).catch(fail))
);
// [{ok: true, value: 1}, {ok: false, error: "something wrong"}, {ok: true, value: 3}];
Само по себе выполнение каждого из промисов продолжается, завершается лишь исполнение
Promise.all()
при первом же режекте.Примерно проследить за поведением
Promise.all()
можно на этом примере:'use strict';
const sleep = (time, v, err = false) => new Promise((resolve, reject) => {
setTimeout(() => {
console.log(`start ${v}, time ${time}`);
if (err) {
console.log(`reject ${v}, time ${time}`);
return void reject(new Error(`REJECTED: ${v}`));
}
console.log(`resolve ${v}, time ${time}`);
resolve(`RESOLVED ${v}`);
}, time * 1000);
});
const promises = [
sleep(2, '1'),
sleep(1, '2'),
sleep(2, '3'),
sleep(4, '4', true),
sleep(3, '5'),
sleep(2, '6'),
sleep(1, '7', true),
sleep(5, '8'),
];
console.log('Begin');
Promise.all(promises)
.then(values => {
console.log(JSON.stringify(values, null, 4));
})
.catch(err => {
console.log(err);
})
.then(() => {
console.log('* Promise.all finished *');
});
console.log('End');
Результат исполнения будет примерно таким:
% node test.js
Begin
End
start 2, time 1
resolve 2, time 1
start 7, time 1
reject 7, time 1
Error: REJECTED: 7
* Promise.all finished *
start 1, time 2
resolve 1, time 2
start 3, time 2
resolve 3, time 2
start 6, time 2
resolve 6, time 2
start 5, time 3
resolve 5, time 3
start 4, time 4
reject 4, time 4
start 8, time 5
resolve 8, time 5
const results = await Promise.all(
array
.map(delayedLog)
.map(promise => promise.catch(err => new SynteticError(e))));
const withError = result.filter(e => e instanceof SynteticError);
Некрасиво, да. try… catch тоже перестанет работать, потому что все ошибки будут обработаны. Но можно сделать обертку вроде promise.Any, который будет кидать массив exception.
await array.reduce((accumulator, item) => accumulator.then(item)), Promise.resolve());
Трюк с reduce имел смысл только до появления await.
github.com/sindresorhus/p-map
И другие от этого автора полезны тем, что позволяют указать concurrency — число одновременно обрабатываемых элементов массива.
for (var i=0; i < array.length; i++) {
await func(array[i])
}
Не модно? Смузями заплюют? Замените var на let — пусть подавятся.
По моему это мертворожденная бесполезная хрень. Не знаю не 1 применения когда стоит её применять, точнее всё случаи когда стоит лучше переписать по другому.
Как вы в таком случае предлагаете читать большой файл под нодой? Варианта как бы только два: либо for await, либо подписка на событие data.
Но в комментарии ниже вы написали, что вам не нравится комбинация })
— значит, остаётся только for await.
Стоп, сувать в forEach анонимную функцию когда есть просто for имхо извращение. ForEach используют когда пишут в функциональном стиле.
Это не говоря о том что фор более гибкий, можно закешировать длину массива ускорив на 10% выполнение, можно через 1 перебирать и тд.
Да и потом чем мешьше вложеных скобок тем читабельнее код, вот от такого
});
нужно избавлсятся
Если нужно обработать момент когда всё итерации разрешатся, то вариант автора статьи единственный адекватный.
когда итерации цикла должны быть параллельными
Вы сами спросили про третий случай по нумерации автора, только через промис олл по другому это костыли типа while(1) и проверять всё итерации на предмет завершения.
async function processArray(array) {
array.forEach(async (item) => {
await func(item);
})
console.log('Done!');
}
Огромное спасибо за статью, без нее тупил бы полдня, не понимая, почему не срабатывает await, у меня ровно такой случай!
Как работать с async/await в циклах JavaScript