> В чем разница между Promise.all, Promise.any и Promise.race в JavaScript (JavaScript)

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

Компании: IT-One, EPAM, Яндекс

Стек: JavaScript

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

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

Promise.all завершается успешно, когда все промисы разрешены, или сразу отклоняется при первом rejection. Promise.race завершается результатом первого завершившегося промиса (любого статуса). Promise.any завершается успешно при первом fulfilled, а отклоняется только если все промисы отклонены. Разница в стратегии обработки множества асинхронных операций.

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

Все три метода принимают iterable промисов и возвращают новый промис, но ведут себя принципиально различно:

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

  • Promise.race: возвращает результат первого завершившегося промиса - неважно, resolve или reject. Если первый завершившийся промис отклоняется, Promise.race отклоняется. Подходит для таймаутов или гонки между несколькими источниками данных.

  • Promise.any: возвращает первый успешно разрешённый промис. Если все промисы отклонены, возвращает AggregateError (массив ошибок). Игнорирует rejection, пока есть хотя бы один успешный. Полезен, когда нужно получить первый успешный ответ из нескольких независимых источников.

Ключевое отличие - Promise.all и Promise.race чувствительны к первому rejection, а Promise.any - нет.

На практике

  • Promise.all - загрузка данных с нескольких эндпоинтов, где каждый обязателен для отображения страницы. Если один запрос падает, показывать частичные данные бессмысленно.
  • Promise.race - установка таймаута для запроса: Promise.race([fetch(url), timeout(5000)]). Если таймаут срабатывает раньше, запрос отменяется.
  • Promise.any - получение данных из нескольких CDN или API-провайдеров. Достаточно первого успешного ответа, остальные игнорируются.

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

Пример кода

JAVASCRIPT
const p1 = Promise.resolve(1);
const p2 = Promise.reject(new Error('ошибка'));
const p3 = new Promise(resolve => setTimeout(() => resolve(3), 100));
// Promise.all - отклоняется при первом rejection
Promise.all([p1, p2, p3])
.then(console.log) // не выполнится
.catch(err => console.log('all rejected:', err.message)); // "ошибка"
// Promise.race - первый завершившийся (p2)
Promise.race([p1, p2, p3])
.then(console.log) // не выполнится
.catch(err => console.log('race rejected:', err.message)); // "ошибка"
// Promise.any - первый успешный (p1)
Promise.any([p1, p2, p3])
.then(result => console.log('any resolved:', result)) // 1
.catch(err => console.log('any rejected:', err.errors));

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

Начни с краткого определения каждого метода, затем перейди к сравнению их поведения при rejection. Приведи практические примеры использования для каждого случая. Упомяни, что Promise.any появился в ES2021 и может требовать полифилла. Покажи понимание, что эти методы не отменяют промисы - они лишь агрегируют результаты. Хорошо упомянуть Promise.allSettled как четвёртый вариант, который ждёт все промисы независимо от статуса.

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

  • Понимание асинхронного управления в JavaScript
  • Умение выбирать правильный инструмент под конкретную задачу
  • Знание нюансов поведения при rejection
  • Осведомлённость о современных возможностях (Promise.any)
  • Понимание, что промисы неотменяемы

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

  • Путать Promise.race и Promise.any: первый реагирует на любой завершившийся промис, второй - только на успешный
  • Думать, что Promise.all возвращает результаты в порядке завершения - на самом деле порядок соответствует исходному массиву
  • Предполагать, что Promise.any отменяет остальные промисы - они продолжают выполняться
  • Забывать про AggregateError в Promise.any при всех rejection
  • Использовать Promise.all там, где достаточно Promise.any (например, при дублировании запросов)

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

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