Почему forEach() не ждёт async-функцию?
forEach() не учитывает возвращаемое значение callback и не содержит механизма ожидания Promise. Поэтому передача async-callback не меняет модель выполнения метода: forEach() синхронно запускает callback для каждого элемента, не ожидая завершения созданных им асинхронных операций:
const users = [1, 2, 3];
users.forEach(async (id) => {
await saveUser(id);
});
console.log("Готово");
"Готово" будет выведено до завершения saveUser(). Каждый вызов async-callback возвращает Promise, но forEach() эти Promise не ожидает и не собирает.
Если операции должны выполняться последовательно, ожидание необходимо сделать частью самого цикла. Для этого подходит for...of с await:
for (const id of users) {
await saveUser(id);
}
console.log("Готово");
Следующая итерация начнётся только после завершения предыдущей. Такой вариант нужен, когда важен порядок выполнения или операции зависят друг от друга.
Для независимых операций можно сформировать массив Promise и дождаться их через Promise.all():
await Promise.all(
users.map((id) => saveUser(id))
);
console.log("Готово");
Promise.all() успешно выполняется после выполнения всех переданных Promise и отклоняется, если хотя бы один из них завершается с ошибкой. При этом остальные уже запущенные операции автоматически не отменяются.
Есть и важное следствие для обработки ошибок: внешний try...catch вокруг forEach() не перехватит последующее отклонение Promise из async-callback:
try {
users.forEach(async (id) => {
await saveUser(id);
});
} catch (error) {
console.error(error);
}
Для управляемой обработки ошибки необходимо ожидать Promise, представляющий выполнение асинхронных операций:
try {
await Promise.all(
users.map((id) => saveUser(id))
);
} catch (error) {
console.error(error);
}
🔥 Проблема не в async внутри forEach(), а в контракте самого метода: forEach() игнорирует возвращаемое значение callback и не ожидает Promise. Для последовательного выполнения используйте for...of с await, для конкурентного выполнения независимых операций — Promise.all().
📣 JS Ready | #практика
forEach() не учитывает возвращаемое значение callback и не содержит механизма ожидания Promise. Поэтому передача async-callback не меняет модель выполнения метода: forEach() синхронно запускает callback для каждого элемента, не ожидая завершения созданных им асинхронных операций:
const users = [1, 2, 3];
users.forEach(async (id) => {
await saveUser(id);
});
console.log("Готово");
"Готово" будет выведено до завершения saveUser(). Каждый вызов async-callback возвращает Promise, но forEach() эти Promise не ожидает и не собирает.
Если операции должны выполняться последовательно, ожидание необходимо сделать частью самого цикла. Для этого подходит for...of с await:
for (const id of users) {
await saveUser(id);
}
console.log("Готово");
Следующая итерация начнётся только после завершения предыдущей. Такой вариант нужен, когда важен порядок выполнения или операции зависят друг от друга.
Для независимых операций можно сформировать массив Promise и дождаться их через Promise.all():
await Promise.all(
users.map((id) => saveUser(id))
);
console.log("Готово");
Promise.all() успешно выполняется после выполнения всех переданных Promise и отклоняется, если хотя бы один из них завершается с ошибкой. При этом остальные уже запущенные операции автоматически не отменяются.
Есть и важное следствие для обработки ошибок: внешний try...catch вокруг forEach() не перехватит последующее отклонение Promise из async-callback:
try {
users.forEach(async (id) => {
await saveUser(id);
});
} catch (error) {
console.error(error);
}
Для управляемой обработки ошибки необходимо ожидать Promise, представляющий выполнение асинхронных операций:
try {
await Promise.all(
users.map((id) => saveUser(id))
);
} catch (error) {
console.error(error);
}
🔥 Проблема не в async внутри forEach(), а в контракте самого метода: forEach() игнорирует возвращаемое значение callback и не ожидает Promise. Для последовательного выполнения используйте for...of с await, для конкурентного выполнения независимых операций — Promise.all().
📣 JS Ready | #практика