Этот вопрос проверяет понимание асинхронного выполнения в JavaScript и различий между методами итерации массивов.
Метод forEach — это синхронный итератор массивов в JavaScript. Когда вы передаёте в него асинхронную функцию (помеченную async), она возвращает промис, но forEach не умеет "ждать" этот промис. Вместо этого он немедленно вызывает следующую итерацию, что приводит к параллельному запуску всех асинхронных операций без гарантии порядка завершения.
Рассмотрим пример:
const delays = [1000, 500, 2000];
async function asyncTask(ms) {
await new Promise(resolve => setTimeout(resolve, ms));
console.log(`Done after ${ms}ms`);
}
console.log('Start');
delays.forEach(async (ms) => {
await asyncTask(ms);
});
console.log('End');Вывод будет: "Start", "End", "Done after 500ms", "Done after 1000ms", "Done after 2000ms". Обратите внимание, что "End" появится сразу, потому что forEach не ждёт завершения асинхронных задач. Задачи выполняются параллельно, и порядок вывода зависит от времени задержки, а не от порядка в массиве.
forEach не прервётся, и ошибку будет сложно поймать.forEach не получится — массив будет пустым.Для последовательного выполнения используйте цикл for...of:
async function processSequentially() {
for (const ms of delays) {
await asyncTask(ms); // Ждём завершения каждой
}
}
Для параллельного выполнения с сохранением результатов подходит Promise.all с map:
async function processInParallel() {
const promises = delays.map(ms => asyncTask(ms));
await Promise.all(promises); // Ждём все сразу
}
Вывод: Используйте forEach только для синхронных операций. Для асинхронного кода выбирайте for...of (последовательно) или Promise.all с map (параллельно), в зависимости от задачи.