> Как обработать ошибку, если хотя бы один из нескольких запросов не ответил в JavaScript? (JavaScript)
Уровень: senior · Роль: frontend · Категория: Технические вопросы
Компании: Яндекс
Стек: JavaScript
> Пример ответа
Короткий ответ
Для обработки ситуации, когда хотя бы один из нескольких запросов не ответил, используйте Promise.allSettled() - он ждёт завершения всех промисов и возвращает массив с результатами каждого (fulfilled/rejected). Если нужна реакция на первую ошибку - Promise.any() (ждёт первого успешного) или Promise.all() с catch на уровне каждого запроса. Для таймаутов комбинируйте с AbortController и Promise.race().
Подробное объяснение
В JavaScript параллельные запросы обрабатываются через комбинации методов Promise. Основная проблема - гарантировать реакцию на ошибку, не блокируя остальные запросы.
Promise.all()- отклоняется при первой ошибке, остальные результаты теряются. Не подходит, если нужно дождаться всех.Promise.allSettled()- ждёт завершения всех, возвращает массив объектов{status, value/reason}. Позволяет обработать каждую ошибку индивидуально.Promise.any()- возвращает первый успешный результат, игнорирует ошибки, пока все не отклонятся (тогда AggregateError).Promise.race()- реагирует на первый завершённый (успех или ошибка). Используется для таймаутов.
Для таймаутов на каждый запрос применяйте AbortController - это стандартный механизм отмены fetch. Комбинируйте с Promise.race(): создаёте промис, который отклоняется через заданное время, и гоняете его с реальным запросом.
На практике
Выбор метода зависит от сценария:
- Если нужно дождаться всех ответов и обработать каждую ошибку -
Promise.allSettled(). - Если достаточно первого успешного ответа (например, несколько CDN) -
Promise.any(). - Если критично получить все данные, но при таймауте одного запроса нужно отменить остальные -
Promise.all()с индивидуальными таймаутами черезAbortController.
Для таймаутов используйте AbortSignal.timeout() (современный браузер) или создавайте свой сигнал с AbortController. Не забывайте очищать таймеры в finally.
Пример кода
JAVASCRIPTasync function fetchWithTimeout(url, timeoutMs = 5000) {const controller = new AbortController();const timeoutId = setTimeout(() => controller.abort(), timeoutMs);try {const response = await fetch(url, { signal: controller.signal });return response.json();} finally {clearTimeout(timeoutId);}}async function handleMultipleRequests(urls) {const results = await Promise.allSettled(urls.map(url => fetchWithTimeout(url)));const errors = results.filter(r => r.status === 'rejected');if (errors.length > 0) {console.error(`Не ответили ${errors.length} запросов:`,errors.map(e => e.reason));// Можно выбросить агрегированную ошибку или продолжить}return results.filter(r => r.status === 'fulfilled').map(r => r.value);}
Как отвечать на собеседовании
Начните с ключевого метода Promise.allSettled() как основного решения. Объясните trade-off между Promise.all() (быстрая ошибка, потеря данных) и Promise.allSettled() (полные данные, ручная обработка ошибок). Упомяните AbortController для таймаутов - это показывает понимание современных API. Если спросят про отмену всех запросов при ошибке одного - расскажите про комбинацию AbortController и Promise.all() с общим сигналом. Не углубляйтесь в полифиллы для старых браузеров, если не спросят.
Что проверяет интервьюер
- Понимание асинхронности и Promise API на уровне senior.
- Умение выбирать правильный инструмент под задачу (allSettled vs all vs any).
- Знание механизмов отмены запросов (AbortController).
- Способность проектировать отказоустойчивые системы с обработкой частичных ошибок.
- Понимание trade-off между производительностью и надёжностью.
Типичные ошибки
- Использование
Promise.all()без обработки ошибок - при первом reject теряются все остальные результаты. - Забывают про таймауты - запрос может висеть бесконечно.
- Путают
Promise.any()иPromise.race()- первый ждёт успеха, второй реагирует на любой исход. - Не очищают таймеры в
finallyпри использованииsetTimeoutсAbortController. - Пытаются обработать ошибки через
.catch()на каждом запросе, но не агрегируют результаты - теряют контекст.
> Похожие задачи по frontend
Как обрабатывать превышение лимита вызовов функции в JavaScript и что возвращать
Как обработать результаты двух асинхронных запросов с условиями success, fail и timeout в JavaScript?
Как обрабатывать массив результатов промисов в JavaScript и выводить success или fail в консоль
Как реализовать декоратор функции в JavaScript, ограничивающий число вызовов и вызывающий колбэк при последнем вызове
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью