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