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

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

Компании: Aston

Стек: JavaScript

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

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

Для параллельных запросов с получением каждого результата используйте Promise.allSettled(). В отличие от Promise.all(), он не прерывается при ошибке и возвращает массив объектов с полями status ("fulfilled" или "rejected") и value или reason. Для простых случаев, когда нужны все успешные результаты, подойдёт Promise.all() с блоком catch.

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

Основные методы для параллельного выполнения промисов:

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

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

  • Promise.race() - возвращает результат первого завершённого промиса (успех или ошибку). Используется для таймаутов.

  • Promise.any() - возвращает первый успешный результат. Если все промисы отклонены, переходит в rejected с AggregateError.

Для параллельного выполнения сами запросы должны быть запущены одновременно (не через await последовательно), а массив промисов передан в один из методов.

На практике

В реальных приложениях выбор метода зависит от бизнес-логики:

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

Важно помнить про обработку ошибок: для Promise.all() используйте catch на уровне всего вызова, для Promise.allSettled() - фильтруйте результаты по status.

Пример кода

JAVASCRIPT
// Параллельные запросы с получением каждого результата
const urls = ['/api/users', '/api/posts', '/api/comments'];
const requests = urls.map(url => fetch(url).then(res => res.json()));
// Вариант 1: Promise.allSettled() - получаем все результаты
Promise.allSettled(requests)
.then(results => {
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(`Успех для ${urls[index]}:`, result.value);
} else {
console.error(`Ошибка для ${urls[index]}:`, result.reason);
}
});
});
// Вариант 2: Promise.all() - если нужны только успешные, но важен порядок
Promise.all(requests)
.then(([users, posts, comments]) => {
console.log('Все данные получены:', { users, posts, comments });
})
.catch(error => {
console.error('Один из запросов упал:', error);
});

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

Начните с прямого ответа - Promise.allSettled(). Объясните разницу между методами и когда какой применять. Приведите пример из реальной практики, где вы выбирали между all и allSettled. Упомяните, что для truly parallel execution сами промисы должны быть созданы до вызова метода (не через await в цикле). Покажите понимание обработки ошибок в каждом случае. Если спросят про производительность - скажите, что все методы запускают промисы конкурентно, разница только в обработке результатов.

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

  • Понимание асинхронности JavaScript и event loop
  • Знание статических методов Promise и их trade-off
  • Умение выбирать правильный инструмент под задачу
  • Навыки обработки ошибок в параллельных операциях
  • Понимание разницы между конкурентным и параллельным выполнением в однопоточном JS

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

  • Использование Promise.all() когда нужны все результаты, включая ошибки - приводит к потере данных при первом же reject
  • Запуск запросов последовательно через await в цикле for...of вместо параллельного запуска
  • Игнорирование обработки ошибок для Promise.all() - отсутствие catch приводит к необработанным rejections
  • Путаница между Promise.allSettled() и Promise.all() в контексте "получить результат каждого"
  • Неправильная интерпретация порядка результатов - все методы возвращают результаты в том же порядке, что и входной массив

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

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