В чем разница последовательных и параллельных запросов и как реализовать параллельные запросы в JavaScript?
Что проверяют
Замечаете ли вы, что цепочка await подряд превращает независимые запросы в очередь. Это одна из самых частых причин медленных экранов.
Как отвечать
Последовательно значит следующий запрос стартует после ответа предыдущего, и время складывается. Параллельно значит все стартуют сразу, и время равно самому долгому.
// последовательно: 300 + 250 + 400 = 950 мс
const user = await getUser();
const orders = await getOrders();
const promos = await getPromos();
// параллельно: примерно 400 мс
const [user, orders, promos] = await Promise.all([getUser(), getOrders(), getPromos()]);Важная деталь: промис стартует в момент создания, а не в момент await. Поэтому достаточно сначала создать все промисы, а ждать их потом.
Что стоит добавить:
- когда параллелить нельзя: второй запрос зависит от результата первого. Тогда очередь неизбежна, и оптимизировать нужно на сервере, отдавая всё одним ответом;
- какой комбинатор брать:
Promise.allпадает целиком при первой ошибке;Promise.allSettledдожидается всех и отдаёт статусы;Promise.anyберёт первый успешный;Promise.raceпервый завершившийся, удобно для тайм-аута; - ограничение параллелизма: сто одновременных запросов упрутся в лимит соединений браузера и в ограничения сервера. Нужен пул, например обработка пачками или библиотека вроде p-limit;
- отмена: при уходе с экрана запросы прерывают через
AbortController, иначе ответы придут в размонтированный компонент.
Где спотыкаются
Пишут await в цикле по массиву и получают время, кратное числу элементов, там где хватило бы Promise.all.
Считают, что Promise.all отменяет остальные запросы при ошибке. Нет, они продолжают выполняться.
Запускают параллельно то, что нагружает один и тот же сервис, и получают ответы медленнее, чем по очереди.