> В чем разница последовательных и параллельных запросов и как реализовать параллельные запросы в JavaScript? (JavaScript)

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

Компании: циан, Яндекс

Стек: JavaScript

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

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

Последовательные запросы выполняются один за другим: каждый следующий ждёт завершения предыдущего. Параллельные запускаются одновременно и завершаются независимо. В JavaScript параллельные запросы реализуются через Promise.all, Promise.allSettled, или с помощью асинхронных итераторов. Ключевое отличие - время выполнения: последовательные суммируют задержки, параллельные ограничены самым медленным запросом. Выбор зависит от зависимостей данных и требований к контролю ошибок.

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

Последовательные запросы (sequential) - это цепочка асинхронных операций, где каждая следующая начинается только после завершения предыдущей. В JavaScript это обычно реализуется через async/await с await внутри цикла или через цепочку .then(). Время выполнения равно сумме времени всех запросов. Используются, когда результат одного запроса нужен для следующего (например, получение user ID, затем его профиля).

Параллельные запросы (parallel/concurrent) запускаются одновременно, без ожидания друг друга. Время выполнения равно времени самого медленного запроса. Реализуются через Promise.all() (все успешны), Promise.allSettled() (все завершены, независимо от результата), Promise.race() (первый завершённый) или через запуск нескольких async функций без await до Promise.all. Важно: параллельные запросы не блокируют event loop, но могут исчерпать лимит соединений браузера (обычно 6 на домен).

Trade-off: последовательные проще в отладке и контроле ошибок, но медленнее. Параллельные быстрее, но требуют управления конкурентностью и обработки частичных ошибок. Для больших объёмов запросов (сотни) нужно ограничивать параллелизм через семафоры или библиотеки типа p-limit.

На практике

Для senior-уровня важно понимать не только базовую разницу, но и нюансы:

  • Promise.all - fail-fast: если один reject, весь промис отклоняется, остальные продолжают выполнение, но их результаты теряются. Для критичных сценариев используйте Promise.allSettled с фильтрацией успешных.
  • Параллельные запросы могут перегрузить сервер или API rate limits - нужна пауза или ограничение конкурентности.
  • В Node.js параллельные запросы к одной БД могут создать deadlock или конфликт транзакций.
  • Для потоковой обработки (например, загрузка чанков) используйте Promise.allSettled с прогресс-баром.
  • В браузере параллельные запросы к разным доменам не имеют лимита, к одному - ограничены (обычно 6). Для обхода используйте domain sharding или HTTP/2 multiplexing.

Пример кода

JAVASCRIPT
// Последовательные запросы
async function sequentialFetch(ids) {
const results = [];
for (const id of ids) {
const res = await fetch(`/api/item/${id}`);
results.push(await res.json());
}
return results;
}
// Параллельные запросы (базовый вариант)
async function parallelFetch(ids) {
const promises = ids.map(id => fetch(`/api/item/${id}`).then(r => r.json()));
return Promise.all(promises);
}
// Параллельные с ограничением конкурентности (3 одновременно)
async function parallelWithLimit(ids, limit = 3) {
const results = [];
const iterator = ids.entries();
const workers = Array(limit).fill().map(async () => {
for (const [index, id] of iterator) {
const res = await fetch(`/api/item/${id}`);
results[index] = await res.json();
}
});
await Promise.all(workers);
return results;
}
// Параллельные с обработкой ошибок (allSettled)
async function parallelWithErrors(ids) {
const results = await Promise.allSettled(
ids.map(id => fetch(`/api/item/${id}`).then(r => r.json()))
);
return results
.filter(r => r.status === 'fulfilled')
.map(r => r.value);
}

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

Начните с чёткого определения: последовательные - по очереди, параллельные - одновременно. Приведите метафору: последовательные как очередь в кассу, параллельные как несколько кассиров. Затем объясните реализацию: async/await для последовательных, Promise.all для параллельных. Упомяните trade-off: скорость vs контроль ошибок. Для senior добавьте про ограничение конкурентности, allSettled, и влияние на сервер. Если спросят про браузер - упомяните лимит соединений и HTTP/2. Не углубляйтесь в микрооптимизации без вопроса.

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

  • Понимание асинхронности и event loop
  • Умение выбирать правильный паттерн под задачу
  • Знание API промисов (all, allSettled, race)
  • Осознание последствий для производительности и надёжности
  • Для senior - способность проектировать масштабируемые решения с контролем конкурентности

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

  • Путают параллельные запросы с параллельным выполнением в JavaScript (которого нет - всё в одном потоке)
  • Используют Promise.all без обработки reject, теряя все результаты при одной ошибке
  • Забывают про лимит соединений браузера при массовых запросах
  • Применяют последовательные запросы там, где данные независимы (теряют производительность)
  • Не учитывают race conditions при параллельной записи в общее состояние

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

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