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

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

Компании: SmartWay

Стек: JavaScript

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

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

Для параллельных запросов с получением всех результатов используйте Promise.all или Promise.allSettled. Promise.all завершится ошибкой при первом rejected промиса, а Promise.allSettled дождётся всех и вернёт массив объектов с полями status и value/reason. Если нужен первый успешный результат - Promise.any, первый завершённый - Promise.race.

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

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

Promise.allSettled (ES2020) ждёт завершения всех промисов независимо от их статуса. Результат - массив объектов {status: "fulfilled", value: ...} или {status: "rejected", reason: ...}. Идеально для сценариев, где нужно обработать каждый ответ индивидуально, например, при загрузке данных из нескольких независимых источников.

Promise.race возвращает первый завершённый промис (любой статус). Promise.any (ES2021) - первый успешный, отклоняет только если все промисы отклонены.

На практике

Для параллельных HTTP-запросов в браузере используйте fetch с Promise.all или Promise.allSettled. Учитывайте лимиты браузера на одновременные соединения (обычно 6 на домен) - при большом количестве запросов применяйте throttling или пакетную обработку. Для отмены запросов используйте AbortController в паре с Promise.race.

Пример кода

JAVASCRIPT
// Параллельные запросы с Promise.all
async function fetchAllUsers(userIds) {
try {
const results = await Promise.all(
userIds.map(id => fetch(`/api/users/${id}`).then(res => res.json()))
);
return results; // массив данных в порядке userIds
} catch (error) {
console.error('Один из запросов упал:', error);
throw error;
}
}
// Promise.allSettled - обрабатываем каждый ответ отдельно
async function fetchWithFallback(urls) {
const results = await Promise.allSettled(
urls.map(url => fetch(url).then(r => r.json()))
);
const successful = results
.filter(r => r.status === 'fulfilled')
.map(r => r.value);
const failed = results
.filter(r => r.status === 'rejected')
.map(r => r.reason);
return { successful, failed };
}

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

Начните с прямого ответа - Promise.all и Promise.allSettled. Кратко объясните разницу: all для критичных запросов, allSettled когда нужно собрать все результаты. Упомяните Promise.race и Promise.any как альтернативы. Приведите пример с fetch и обработкой ошибок. Если спросят про производительность, скажите о лимите соединений и throttling. Не углубляйтесь в детали реализации V8 или event loop, если не спросят.

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

  • Понимание асинхронности и промисов на уровне выше базового
  • Умение выбирать правильный метод под задачу (все результаты vs первый успешный)
  • Знание современных возможностей (allSettled, any)
  • Практический опыт с обработкой ошибок в параллельных запросах
  • Понимание trade-off между all и allSettled

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

  • Использовать Promise.all когда нужны все результаты, включая ошибки - лучше allSettled
  • Забывать, что Promise.all отклоняется при первой же ошибке, теряя остальные результаты
  • Не обрабатывать reject внутри map, из-за чего Promise.all падает целиком
  • Путать Promise.race и Promise.any - первый берёт любой завершённый, второй только успешный
  • Игнорировать лимиты браузера на параллельные соединения при массовых запросах

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

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