Promise.any в JavaScript: первый успешный результат и общий отказ

Promise.any в JavaScript: первый успешный результат и общий отказ
Содержание статьи

Promise.any подходит, когда достаточно первого успешно выполненного промиса. Ранний отказ одной операции не завершает общий результат, пока другие ещё могут выполниться успешно. В практикуме Mentoring.digital проверим это без сети, на управляемых задержках.

Первый завершившийся и первый успешный отличаются

Promise.race принимает исход первого завершившегося промиса, включая отказ. Promise.any ждёт первый успех и отклоняется только тогда, когда отклонены все входные промисы.

const later = (delay, value, fail = false) =>
  new Promise((resolve, reject) => {
    setTimeout(() => {
      if (fail) reject(value);
      else resolve(value);
    }, delay);
  });

const value = await Promise.any([
  later(10, "first request failed", true),
  later(30, "available copy"),
  later(60, "another copy"),
]);
console.log(value); // available copy

Запустите пример в модуле JavaScript с поддержкой await на верхнем уровне, например в файле .mjs в Node.js. При обычном скрипте поместите код с await внутрь async-функции.

Как разобрать общий отказ

Если все операции отклонены, результатом становится AggregateError. Массив errors содержит причины в порядке входных промисов, а не в порядке времени их завершения.

try {
  await Promise.any([
    later(30, "A failed", true),
    later(10, "B failed", true),
  ]);
} catch (error) {
  if (!(error instanceof AggregateError)) throw error;
  console.log(error.errors); // ['A failed', 'B failed']
}

try {
  await Promise.any([]);
} catch (error) {
  console.log(error.errors); // []
}

Причина отказа промиса не обязана быть объектом Error: в учебном примере переданы строки. В рабочем коде сохраняйте контекст операции и не рассчитывайте, что у каждой причины есть поле message. Пустой набор тоже приводит к отказу, поэтому его полезно проверить до запуска.

Оставшиеся операции продолжаются

Получение первого успеха не отменяет другие запросы и таймеры. Если они расходуют ресурсы, продумайте отдельный механизм отмены, который поддерживает используемый API. Promise.any сам такую отмену не выполняет.

При работе с fetch отдельно определите, какой HTTP-ответ считать успехом: полученный ответ с ошибочным статусом требует проверки приложением. Иначе можно выбрать ответ, который формально получен, но не подходит задаче.

Упражнение для выбора метода

Поменяйте местами задержки успехов, затем сделайте все исходы ошибочными. Сравните Promise.any с Promise.race на том же наборе. Для каждого варианта заранее запишите ожидаемый результат и проверьте, требуется ли вам первый успех или исход первой завершившейся операции.

Разобрать асинхронные сценарии можно на курсе JavaScript, а обработку ошибок приложения проверить с наставником по JavaScript.

Похожие статьи по данной теме