> Как определить момент завершения всех промисов с ошибками для вызова reject в JavaScript? (JavaScript)
Уровень: senior · Роль: frontend · Категория: Технические вопросы
Компании: Яндекс
Стек: JavaScript
> Пример ответа
Короткий ответ
Для определения момента завершения всех промисов с ошибками используйте Promise.allSettled(). Он ждёт выполнения всех промисов независимо от результата и возвращает массив объектов с полями status, value или reason. Если нужен reject при первой же ошибке - Promise.all(). Для кастомной логики сбора ошибок подойдёт Promise.all() в комбинации с map и обработкой каждого промиса через .catch.
Подробное объяснение
В JavaScript есть несколько способов работы с группой промисов, и выбор зависит от требуемого поведения при ошибках:
-
Promise.all()- завершается reject при первой ошибке, не дожидаясь остальных промисов. Это подходит, когда любая ошибка критична и дальнейшее выполнение не имеет смысла. -
Promise.allSettled()- ждёт завершения всех промисов, возвращая массив результатов. Каждый элемент содержитstatus: "fulfilled"или"rejected", а такжеvalueилиreason. Идеален, когда нужно обработать все результаты, включая ошибки. -
Promise.any()- завершается resolve при первом успешном промисе, reject - только если все промисы отклонены. Полезен для race-условий с fallback. -
Promise.race()- завершается при первом завершённом промисе (любого статуса). Используется для таймаутов.
Для кастомного сбора ошибок можно обернуть каждый промис в конструкцию, которая никогда не reject'ится, а накапливает ошибки в массиве:
JAVASCRIPTfunction reflect(promise) {return promise.then(value => ({ status: 'fulfilled', value }),reason => ({ status: 'rejected', reason }));}
Этот паттерн лежит в основе Promise.allSettled().
На практике
В реальных проектах выбор метода зависит от сценария:
-
Загрузка данных для UI: используйте
Promise.allSettled(), чтобы показать частично загруженную страницу с индикацией ошибок по отдельным блокам. -
Валидация формы с несколькими async-проверками:
Promise.all()с reject при первой ошибке, чтобы сразу показать пользователю проблему. -
Параллельные запросы к API с fallback-серверами:
Promise.any()для автоматического переключения. -
Таймаут для запроса:
Promise.race()с промисом, который reject'ится через заданное время.
Важно помнить, что Promise.allSettled() появился в ES2020. Для старых окружений требуется полифилл или ручная реализация через reflect.
Пример кода
JAVASCRIPT// Сценарий: загрузка данных для дашбордаconst fetchUser = fetch('/api/user').then(r => r.json());const fetchOrders = fetch('/api/orders').then(r => r.json());const fetchStats = fetch('/api/stats').then(r => r.json());// Вариант 1: все или ничегоPromise.all([fetchUser, fetchOrders, fetchStats]).then(([user, orders, stats]) => renderDashboard(user, orders, stats)).catch(err => showErrorPage(err));// Вариант 2: частичная загрузка с ошибкамиPromise.allSettled([fetchUser, fetchOrders, fetchStats]).then(results => {const data = results.map(r =>r.status === 'fulfilled' ? r.value : null);renderDashboardWithFallbacks(data);});// Вариант 3: кастомный сбор ошибокconst promises = [fetchUser, fetchOrders, fetchStats];const errors = [];Promise.all(promises.map(p =>p.catch(err => { errors.push(err); return null; }))).then(results => {if (errors.length) notifyErrors(errors);renderDashboard(results);});
Как отвечать на собеседовании
Начните с прямого ответа: Promise.allSettled() для ожидания всех промисов с ошибками. Затем объясните trade-off между разными методами. Покажите понимание, когда какой метод применять. Упомяните, что Promise.allSettled() - это сахар над паттерном reflect. Если спросят про старые браузеры, предложите полифилл или ручную реализацию. Не углубляйтесь в микрооптимизации - сфокусируйтесь на семантике и практической применимости.
Что проверяет интервьюер
- Понимание асинхронности и жизненного цикла промисов
- Знание стандартных методов Promise API и их различий
- Умение выбирать правильный инструмент под задачу
- Понимание edge cases: утечки памяти, порядок выполнения, обработка ошибок
- Способность объяснить trade-off между подходами
Типичные ошибки
- Использование
Promise.all()когда нужно дождаться всех результатов, включая ошибки - Забывание, что
Promise.all()reject'ится немедленно при первой ошибке - Путаница между
Promise.allSettled()иPromise.any() - Отсутствие обработки ошибок в каждом промисе при кастомном сборе
- Предположение, что промисы выполняются последовательно при использовании
Promise.all()- на самом деле они запускаются параллельно
> Похожие задачи по frontend
Как повесить обработчик на резолв каждого промиса в массиве для реализации any?
Почему нельзя просто вернуть Promise.resolve с промисом внутри в реализации any?
В каком порядке выполняются промисы и их обработчики then/catch в JavaScript и как это влияет на порядок ошибок?
Как обработать успешное разрешение одного из промисов в функции any?
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью