> В чем разница Promise.all и Promise.allSettled в JavaScript и что происходит если один промис падает (JavaScript)

Уровень: senior · Роль: frontend · Категория: Технические вопросы

Компании: Cyber Interactive, Kodix

Стек: JavaScript

> Пример ответа

Короткий ответ

Promise.all отклоняется сразу, как только любой из переданных промисов падает - результат остальных теряется, и управление уходит в catch. Promise.allSettled ждёт завершения всех промисов и всегда возвращает массив с объектами {status, value} или {status, reason} - даже если часть промисов отклонилась. Разница в стратегии обработки ошибок: all - fail-fast, allSettled - дождаться всех исходов.

Подробное объяснение

Promise.all принимает итерируемую коллекцию промисов и возвращает новый промис, который резолвится массивом результатов в том же порядке. Если хотя бы один промис отклоняется, Promise.all немедленно отклоняется с причиной первого упавшего промиса. Остальные промисы продолжают выполняться, но их результаты игнорируются - вы не получите ни их значений, ни их ошибок.

Promise.allSettled появился в ES2020 и решает именно эту проблему. Он ждёт, пока все промисы завершатся (и резолвятся, и отклонятся), и возвращает массив объектов с полем status. Для успешных - {status: 'fulfilled', value}, для отклонённых - {status: 'rejected', reason}. Порядок элементов соответствует порядку исходных промисов.

Ключевое различие - семантика: all подходит, когда вам нужен либо полный набор результатов, либо ошибка как можно раньше. allSettled - когда важно получить все исходы, даже если часть операций провалилась (например, массовая отправка запросов, где не хочется терять частичный результат).

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

На практике

В реальных задачах Promise.all часто используют для параллельной загрузки независимых данных, когда отсутствие одного блока делает страницу бесполезной. allSettled - для панелей мониторинга, где нужно показать статус каждого сервиса, даже если один из них недоступен.

Типичный сценарий для allSettled - валидация массива файлов перед загрузкой: вы хотите узнать, какие файлы прошли проверку, а какие нет, не прерывая проверку остальных.

Ещё один нюанс: Promise.all с пустым массивом резолвится пустым массивом, allSettled - тоже пустым массивом. Но Promise.all с массивом, содержащим null или undefined, обработает их как уже зарезолвленные значения.

Пример кода

JAVASCRIPT
const p1 = Promise.resolve(1);
const p2 = Promise.reject(new Error('boom'));
const p3 = Promise.resolve(3);
// Promise.all - fail-fast
Promise.all([p1, p2, p3])
.then(results => console.log('all results:', results))
.catch(err => console.log('all failed:', err.message));
// all failed: boom
// Promise.allSettled - ждёт все
Promise.allSettled([p1, p2, p3])
.then(results => console.log('settled:', results));
// settled: [
// {status: 'fulfilled', value: 1},
// {status: 'rejected', reason: Error('boom')},
// {status: 'fulfilled', value: 3}
// ]

Как отвечать на собеседовании

Начните с главного отличия: all отклоняется при первой ошибке, allSettled возвращает все исходы. Затем приведите конкретный сценарий, где каждое из них уместно. Покажите, что понимаете поведение при частичном падении: в all вы теряете доступ к успешным результатам, в allSettled - получаете полную картину.

Если спросят про производительность - упомяните, что оба запускают промисы параллельно, разница только в обработке результатов. Можно добавить, что allSettled чуть дороже из-за обёртки каждого результата в объект, но это незначительно.

Хорошо, если вы упомянете, что Promise.all удобен для "всё или ничего", а allSettled - для "собрать статистику". Также можно отметить, что в all ошибка первого упавшего промиса - это единственная ошибка, которую вы получите, даже если упадут несколько.

Что проверяет интервьюер

Интервьюер проверяет понимание асинхронности и обработки ошибок в JavaScript. Конкретно:

  • знаете ли вы семантику fail-fast в Promise.all
  • понимаете ли, что allSettled не отклоняется никогда (кроме случая, когда сам вызов синхронно бросает исключение, например, при передаче неитерируемого объекта)
  • умеете ли выбирать правильный инструмент под задачу
  • понимаете ли разницу между value и reason в результатах allSettled

Также это косвенно проверяет ваше знание современного стандарта ES2020 и умение работать с несколькими параллельными операциями.

Типичные ошибки

  • Утверждение, что allSettled "ловит" ошибки - на самом деле он просто возвращает их в reason, не вызывая catch
  • Забывают, что Promise.all не отменяет остальные промисы при падении одного - они продолжают выполняться в фоне
  • Путают allSettled с any - any ждёт первый успешный, а не все
  • Используют allSettled там, где нужен fail-fast, и наоборот - например, в критичной цепочке загрузки, где отсутствие одного модуля делает всё бессмысленным
  • Не учитывают, что allSettled возвращает массив объектов, а не плоский массив значений - нужно извлекать value или reason вручную

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью