Как обрабатывать случаи отклонения одного из промисов в Promise.all в JavaScript?
Что проверяют
Знаете ли вы, что делать, когда часть данных получить не удалось, и понимаете ли, что остальные запросы при этом не отменяются.
Как отвечать
Есть три подхода, и выбор зависит от того, нужен ли частичный результат.
Нужны все данные, иначе смысла нет: оставляем Promise.all и ловим ошибку целиком.
try {
const [user, orders] = await Promise.all([loadUser(), loadOrders()]);
} catch (e) {
showError(e); // первая же ошибка приводит сюда
}Нужен частичный результат: берём Promise.allSettled, который дожидается всех и никогда не отклоняется.
const results = await Promise.allSettled([loadUser(), loadOrders(), loadPromos()]);
const [user, orders, promos] = results.map((r) => (r.status === "fulfilled" ? r.value : null));
const failed = results.filter((r) => r.status === "rejected").map((r) => r.reason);Нужны значения по умолчанию: обернуть каждый промис своим catch, чтобы неудача превращалась в запасное значение. Тогда Promise.all не отклонится вовсе.
Что обязательно проговорить:
- отклонение не отменяет остальные запросы: они продолжают выполняться, а их ошибки могут стать необработанными отклонениями. Настоящая отмена делается через
AbortController; Promise.allтеряет успешные результаты при ошибке: в обработчик приходит только причина, а данные, которые уже пришли, недоступны. Это главный довод в пользуallSettled, когда экран может работать частично;- соседи:
Promise.anyберёт первый успешный и отклоняется сAggregateError, если упали все;Promise.raceзавершается первым завершившимся, что удобно для тайм-аута.
Где спотыкаются
Обёртывают каждый промис в catch, возвращающий undefined, и потом не отличают «нет данных» от «была ошибка».
Считают, что после отклонения остальные запросы прекращаются.
Показывают пустой экран целиком из-за неудачи одного второстепенного блока.