Gernar
JavaScript: асинхронность

Что такое Promise.race

Разбор вопроса «Что такое Promise.race» для Frontend Developer: что проверяет интервьюер, ключевые тезисы, практические примеры и частые ошибки.

Вопрос

Что такое Promise.race

Профессия

Frontend Developer

Что хочет услышать интервьюер

Интервьюер хочет убедиться, что кандидат понимает назначение Promise.race, его поведение и практическое применение. Также важно, чтобы кандидат мог объяснить, как этот метод отличается от других методов работы с промисами, таких как Promise.all.

Ключевые тезисы

  • Promise.race — это метод, который принимает массив промисов и возвращает новый промис.
  • Этот новый промис завершается (resolved или rejected) как только завершается первый промис из переданного массива.
  • Результат Promise.race — это результат первого завершенного промиса, независимо от его статуса (успех или ошибка).
  • Пример использования: контроль времени выполнения асинхронных операций или реализация тайм-аутов.

Подробный ответ

Promise.race — это метод, который принимает массив промисов и возвращает новый промис. Этот новый промис завершается (resolved или rejected) как только завершается первый промис из переданного массива. Результат Promise.race — это результат первого завершенного промиса, независимо от его статуса (успех или ошибка). Это полезно в сценариях, где важно получить результат самого быстрого промиса, например, при реализации тайм-аутов или выборе между несколькими источниками данных.

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

Важно отметить, что Promise.race не отменяет остальные промисы — они продолжают выполняться в фоне, но их результаты игнорируются. Это может привести к утечкам ресурсов, если не учитывать этот аспект.

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

Практические примеры

Пример 1

Пример с тайм-аутом запроса:

const fetchWithTimeout = (url, timeout) => {
  const fetchPromise = fetch(url);
  const timeoutPromise = new Promise((_, reject) => {
    setTimeout(() => reject(new Error('Request timeout')), timeout);
  });
  return Promise.race([fetchPromise, timeoutPromise]);
};

// Использование: fetchWithTimeout('https://api.example.com/data', 5000)

.then(response => console.log(response))
  .catch(error => console.error(error));

Пример 2

Пример выбора между несколькими источниками данных:

const source1 = fetch('https://source1.example.com/data');
const source2 = fetch('https://source2.example.com/data');

Promise.race([source1, source2])
  .then(data => console.log('First response:', data))
  .catch(error => console.error('First error:', error));

Частые ошибки

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

Связанные темы

  • Promise.all — ждет завершения всех промисов или первого отклоненного
  • Promise.any — завершается при первом успешном промисе (из ES2021)
  • Promise.allSettled — ждет завершения всех промисов независимо от их статуса
  • Async/await — современный синтаксис для работы с промисами

Follow-up вопросы

Как можно использовать Promise.race для реализации тайм-аута запроса?

Уровень: intermediate

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

Что произойдет, если передать пустой массив в Promise.race?

Уровень: basic

Promise.race с пустым массивом вернет промис, который никогда не разрешится, так как нет ни одного промиса для соревнования.

Чем отличается поведение Promise.race от Promise.any?

Уровень: intermediate

Promise.race завершается с результатом первого завершенного промиса (независимо от успеха или ошибки), а Promise.any ждет первого успешно выполненного промиса, игнорируя отклонения, пока есть хотя бы один unresolved промис.

Как обработать ошибку в Promise.race, если первый завершенный промис отклонен?

Уровень: basic

Нужно использовать .catch() или try/catch в async/await. Ошибка будет содержать причину отклонения первого промиса, и ее можно обработать соответствующим образом.

Можно ли использовать Promise.race для отмены асинхронных операций? Какие есть ограничения?

Уровень: advanced

Promise.race не отменяет операции — остальные промисы продолжают выполняться. Для настоящей отмены нужно использовать AbortController или аналогичные механизмы, особенно для fetch-запросов.

Содержание