forked from templates/nextjs-template
95 lines
3.3 KiB
Markdown
95 lines
3.3 KiB
Markdown
---
|
||
title: Параллельные серверные запросы
|
||
description: Как запускать независимые REST-запросы на сервере без waterfall.
|
||
keywords: [rest, promise.all, параллельные запросы, server components]
|
||
---
|
||
|
||
# Параллельные серверные запросы
|
||
|
||
Если серверному компоненту нужно несколько независимых данных, запускайте запросы до ожидания результата. Последовательный `await` создаёт waterfall и замедляет рендер.
|
||
|
||
## Когда использовать
|
||
|
||
- Запросы независимы друг от друга.
|
||
- Все данные нужны текущему серверному компоненту перед возвратом UI.
|
||
- Нельзя или не нужно стримить часть UI отдельно.
|
||
|
||
## Хорошо
|
||
|
||
```tsx
|
||
import { petStoreApi, StatusEnum } from 'infra/pet-store-api'
|
||
import { PetsDashboardScreen } from 'screens/pets-dashboard'
|
||
|
||
export default async function PetsDashboardPage() {
|
||
const availablePetsPromise = petStoreApi.pet.findPetsByStatus({
|
||
status: StatusEnum.Available,
|
||
})
|
||
const pendingPetsPromise = petStoreApi.pet.findPetsByStatus({
|
||
status: StatusEnum.Pending,
|
||
})
|
||
const soldPetsPromise = petStoreApi.pet.findPetsByStatus({
|
||
status: StatusEnum.Sold,
|
||
})
|
||
|
||
const [availablePets, pendingPets, soldPets] = await Promise.all([
|
||
availablePetsPromise,
|
||
pendingPetsPromise,
|
||
soldPetsPromise,
|
||
])
|
||
|
||
return (
|
||
<PetsDashboardScreen
|
||
availablePets={availablePets}
|
||
pendingPets={pendingPets}
|
||
soldPets={soldPets}
|
||
/>
|
||
)
|
||
}
|
||
```
|
||
|
||
## Плохо
|
||
|
||
```tsx
|
||
export default async function PetsDashboardPage() {
|
||
const availablePets = await petStoreApi.pet.findPetsByStatus({
|
||
status: StatusEnum.Available,
|
||
})
|
||
const pendingPets = await petStoreApi.pet.findPetsByStatus({
|
||
status: StatusEnum.Pending,
|
||
})
|
||
const soldPets = await petStoreApi.pet.findPetsByStatus({
|
||
status: StatusEnum.Sold,
|
||
})
|
||
|
||
return (
|
||
<PetsDashboardScreen
|
||
availablePets={availablePets}
|
||
pendingPets={pendingPets}
|
||
soldPets={soldPets}
|
||
/>
|
||
)
|
||
}
|
||
```
|
||
|
||
Во втором примере каждый следующий запрос ждёт предыдущий, хотя они независимы.
|
||
|
||
## Зависимые запросы
|
||
|
||
Если второй запрос зависит от результата первого, последовательный `await` допустим:
|
||
|
||
```tsx
|
||
export default async function OrderPage({ params }: OrderPageProps) {
|
||
const { id } = await params
|
||
const order = await petStoreApi.store.getOrderById({ orderId: Number(id) })
|
||
const pet = await petStoreApi.pet.getPetById({ petId: order.petId })
|
||
|
||
return <OrderScreen order={order} pet={pet} />
|
||
}
|
||
```
|
||
|
||
Не превращайте зависимый сценарий в `Promise.all` искусственно.
|
||
|
||
## Когда выбрать другую стратегию
|
||
|
||
Если часть данных не обязательна для первого блока UI, можно запустить промис выше и передать его ниже: [Передача промиса ниже](./pass-promise-down.md).
|