Работ асинхронных циклов в JavaScript
Асинхронные операции сбивают с толку многих разработчиков.
Сочетание асинхронного цикла с циклом for (или for…of), возможно, является наиболее простым вариантом при выполнении асинхронных операций над элементами массива. Использование await внутри цикла for приведет к остановке кода и ожиданию завершения асинхронного выполнения кода, это означает, что все промисы будут выполняться последовательно.
const asyncUppercase = item =>
new Promise(resolve =>
setTimeout(
() => resolve(item.toUpperCase()),
Math.floor(Math.random() * 1000)
)
);
const uppercaseItems = async () => {
const items = ['a', 'b', 'c'];
for (item of items) {
const uppercaseItem = await asyncUppercase(item);
console.log(uppercaseItem);
}
console.log('Items processed');
};
uppercaseItems();
// LOGS: 'A', 'B', 'C', 'Items processed'
Промисы
Promise.all() предоставляет еще один вариант для асинхронных циклов по массивам. Основное отличие от предыдущего примера заключается в том, что Promise.all() выполняет все асинхронные операции параллельно. Это означает, что промисы будут выполняться не по порядку, что в некоторых случаях может быть проблемой. Чаще всего это предпочтительное решение, поскольку довольно редко требуется, чтобы промисы выполнялись последовательно.
const asyncUppercase = item =>
new Promise(resolve =>
setTimeout(
() => resolve(item.toUpperCase()),
Math.floor(Math.random() * 1000)
)
);
const uppercaseItems = () => {
const items = ['a', 'b', 'c'];
return Promise.all(
items.map(async item => {
const uppercaseItem = await asyncUppercase(item);
console.log(uppercaseItem);
})
).then(() => {
console.log('Items processed');
});
};
// LOGS: 'A', 'C', 'B', 'Items processed'
Методы массива
К сожалению, методы массива, такие как Array.prototype.forEach(), плохо работают с async/await. Единственное жизнеспособное решение — использовать Promise.all(), как показано в предыдущем примере. Использование асинхронного обратного вызова с Array.prototype.forEach() приведет к тому, что часть кода будет выполняться, но awaite работать не будет.
const asyncUppercase = item =>
new Promise(resolve =>
setTimeout(
() => resolve(item.toUpperCase()),
Math.floor(Math.random() * 1000)
)
);
const uppercaseItems = async () => {
const items = ['a', 'b', 'c'];
await items.forEach(async item => {
const uppercaseItem = await asyncUppercase(item);
console.log(uppercaseItem);
});
console.log('Items processed');
};
uppercaseItems();
// LOGS: ''Items processed', 'B', 'A', 'C'