> Каким методом промиса получить результат первого выполненного запроса (JavaScript)

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

Компании: SmartWay

Стек: JavaScript

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

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

Для получения результата первого выполненного запроса используется статический метод Promise.race(). Он принимает итератор промисов и возвращает новый промис, который разрешается или отклоняется значением первого завершившегося (settled) промиса. Важно: если первый завершившийся промис будет rejected, то Promise.race() тоже завершится с ошибкой, игнорируя успешные результаты остальных.

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

Promise.race() - один из статических методов Promise API. Его суть: из переданного списка промисов возвращается результат того, который завершится первым (как resolve, так и reject). Это поведение отличается от Promise.any(), который ждёт первого успешного (fulfilled) результата, игнорируя reject до первого resolve.

Механизм работы:

  • Все промисы запускаются параллельно
  • Как только любой из них переходит в состояние settled (fulfilled или rejected), Promise.race() немедленно завершается с тем же результатом
  • Остальные промисы продолжают выполняться, но их результаты игнорируются

Этот метод полезен для:

  • Таймаутов: комбинируем запрос с промисом, который отклоняется через заданное время
  • Гонки запросов к разным источникам данных (например, CDN)
  • Получения самого быстрого ответа от нескольких серверов

На практике

В реальных проектах Promise.race() часто используют для реализации таймаутов:

JAVASCRIPT
const fetchWithTimeout = (url, timeout = 5000) => {
const controller = new AbortController();
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => {
controller.abort();
reject(new Error('Request timed out'));
}, timeout);
});
return Promise.race([
fetch(url, { signal: controller.signal }),
timeoutPromise
]);
};

Также применяется для выбора самого быстрого источника данных:

JAVASCRIPT
const getFastestResponse = async (urls) => {
const promises = urls.map(url => fetch(url).then(r => r.json()));
return Promise.race(promises);
};

Пример кода

JAVASCRIPT
// Пример с разным временем выполнения
const slowPromise = new Promise(resolve =>
setTimeout(() => resolve('медленный'), 3000)
);
const fastPromise = new Promise(resolve =>
setTimeout(() => resolve('быстрый'), 1000)
);
Promise.race([slowPromise, fastPromise])
.then(result => console.log(result)); // 'быстрый'
// Пример с ошибкой
const errorPromise = Promise.reject(new Error('ошибка'));
const successPromise = Promise.resolve('успех');
Promise.race([errorPromise, successPromise])
.then(result => console.log(result))
.catch(err => console.error(err.message)); // 'ошибка'

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

Начни с чёткого определения: Promise.race() возвращает результат первого завершившегося промиса, независимо от его статуса. Подчеркни разницу с Promise.any() (первый успешный) и Promise.allSettled() (все результаты). Приведи реальный кейс - таймаут для fetch. Упомяни, что остальные промисы не отменяются, а продолжают выполняться в фоне, что может быть проблемой для производительности. Если собеседник спросит про альтернативы, скажи, что для отмены запросов лучше использовать AbortController в комбинации с Promise.race().

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

  • Понимание различий между race, any, all и allSettled
  • Знание edge cases: что будет, если первый промис rejected
  • Умение применять метод в реальных сценариях (таймауты, fallback-запросы)
  • Понимание асинхронного выполнения и event loop (промисы не отменяются)
  • Способность объяснить trade-off: скорость vs надёжность

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

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

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

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