refactor: перенести сборку в проекты
All checks were successful
CI/CD Pipeline / build (push) Successful in 39s
CI/CD Pipeline / docker (push) Successful in 1m30s
CI/CD Pipeline / deploy (push) Successful in 8s

- перенесены каноны и VitePress-конфиги в projects/<slug>

- добавлены корневой и проектные build.ts для сборки артефактов

- добавлены shared-библиотеки сборки в projects/_shared/lib

- обновлены CI, Dockerfile, package.json, gitignore и README

- удалена сборка frontend-агента
This commit is contained in:
2026-05-22 19:07:10 +03:00
parent a53c5fc1b1
commit bdb99ade62
117 changed files with 442 additions and 568 deletions

View File

@@ -0,0 +1,94 @@
---
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).