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, можно запустить промис выше и передать его ниже: [Передача промиса ниже](/docs/applied/data-fetch/pass-promise-down).
|