Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Чому forEach з async-колбеком не чекає і як обробити масив асинхронно з обмеженням паралельності?

forEach викликає колбек і ігнорує те, що він повертає. async-колбек повертає Promise, який ніхто не чекає: цикл завершується одразу, помилки губляться.

items.forEach(async (item) => { await save(item); });
console.log('готово'); // виведеться ДО того, як щось збережеться

Правильні варіанти залежно від задачі:

// Послідовно, по одному
for (const item of items) {
  await save(item);
}

// Усі паралельно
await Promise.all(items.map((item) => save(item)));

Проблема «всіх паралельно»: тисяча елементів - тисяча одночасних запитів. API почне відповідати 429, браузер обмежить кількість з'єднань, база отримає піку навантаження.

Обмежена паралельність - не більше N одночасно:

async function mapLimit(items, limit, fn) {
  const results = new Array(items.length);
  let next = 0;

  async function worker() {
    while (next < items.length) {
      const index = next++;
      results[index] = await fn(items[index], index);
    }
  }

  await Promise.all(Array.from({ length: Math.min(limit, items.length) }, worker));
  return results;
}

const saved = await mapLimit(items, 5, save);

Тут next++ безпечний, бо JavaScript однопотоковий: між читанням і збільшенням лічильника інший «воркер» виконатися не може.

На практиці часто беруть готові бібліотеки (p-limit, p-map), які додають ще й обробку помилок і скасування.

Докладніше в документації: Array.prototype.forEach

1

Перевір себе

20 випадкових питань за спробу, після завершення - розбір кожної помилки

Схожі питання