# Angular @defer у 2026: декларативне ледаче завантаження для швидших застосунків
> Опануйте блоки @defer в Angular для декларативного ледачого завантаження. Глибокий розбір тригерів, prefetching, інкрементальної гідратації, поведінки в SSR і практичних патернів продуктивності.
- Published: 2026-06-14
- Updated: 2026-06-17
- Author: Anthony Fillion-Maillet
- Tags: angular, angular-defer, lazy-loading, performance, ssr, signals, deep-dive
- Reading time: 9 min
---
Блоки `@defer` в Angular вирішують проблему, яку ледаче завантаження на основі роутера ніколи не могло вирішити: завантаження окремих компонентів, директив і пайпів на вимогу без реструктуризації застосунку на окремі маршрути. Представлений в Angular 17 і стабілізований у версії 22, `@defer` перетворює те, що раніше вимагало динамічних імпортів, прапорців `*ngIf` і налаштування webpack, на єдиний декларативний блок шаблону.
> **Що робить @defer**
>
> `@defer` вказує компілятору Angular розділити обгорнуті компоненти на окремі фрагменти JavaScript (chunks), які завантажуються лише після спрацювання умови тригера. Браузер завантажує менше JavaScript на старті, що покращує Largest Contentful Paint (LCP) і Time to First Byte (TTFB) без ручного налаштування code-splitting.
## Як @defer працює під капотом
Коли компілятор Angular зустрічає блок `@defer`, він виокремлює кожен самостійний (standalone) компонент, директиву та пайп усередині нього в окремий фрагмент. Основний бандл постачається без цих залежностей. Під час виконання Angular оцінює умову тригера й отримує фрагмент через динамічний виклик `import()`.
Блок підтримує чотири підблоки, які контролюють те, що бачить користувач протягом життєвого циклу завантаження:
```typescript
// app.component.html
@defer (on viewport) {
} @placeholder {
} @loading (minimum 200ms) {
} @error {
Failed to load the dashboard. Please refresh.
}
```
`@placeholder` рендериться до спрацювання тригера. `@loading` зʼявляється під час завантаження фрагмента, з опціональною тривалістю `minimum`, щоб запобігти мерехтінню (flicker). `@error` перехоплює мережеві помилки або помилки фрагмента. Параметр `minimum` у `@loading` запобігає спалаху спінера, коли фрагмент швидко завантажується з кешу.
Одне обмеження: кожна залежність усередині `@defer` має бути standalone. Компоненти, що не є standalone та оголошені в `NgModule`, не можна відкласти, і вони завантажаться жадібно (eagerly) незалежно від обгортки `@defer`.
## Типи тригерів: контроль моменту завантаження компонентів
Angular надає сім вбудованих тригерів, кожен з яких відповідає за іншу стратегію завантаження. Кілька тригерів можна обʼєднати крапками з комою, і вони оцінюються як умови OR.
```typescript
// product-page.component.html
// Loads when the browser goes idle (default)
@defer {
}
// Loads when the element enters the viewport
@defer (on viewport) {
}
// Loads on click or keydown
@defer (on interaction) {
} @placeholder {
}
// Loads on mouseenter or focusin
@defer (on hover) {
}
// Loads after 3 seconds
@defer (on timer(3s)) {
}
// Loads immediately after initial render
@defer (on immediate) {
}
```
Тригер `on viewport` внутрішньо використовує [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API). Тригер `on idle` делегує до `requestIdleCallback`, що робить його найбезпечнішим типовим вибором для контенту нижче лінії згину (below-the-fold). Тригер `on timer` приймає тривалість у мілісекундах (`500ms`) або секундах (`3s`).
### Тригер `when` для реактивних умов
Окрім тригерів на основі подій, `when` приймає будь-який булевий вираз, включно зі зчитуванням сигналів:
```typescript
// dashboard.component.ts
export class DashboardComponent {
showAdvanced = signal(false);
}
// dashboard.component.html
@defer (when showAdvanced()) {
} @placeholder {
}
```
Поєднання `on` і `when` є допустимим. Angular трактує їх як OR: блок завантажується, коли виконано будь-яку з умов.
## Prefetching: відокремлення завантаження від відображення
Prefetching відокремлює момент завантаження фрагмента від моменту рендерингу компонента. Це усуває відчутну затримку, отримуючи JavaScript ще до того, як користувач його активує.
```typescript
// settings.component.html
@defer (on interaction; prefetch on idle) {
} @placeholder {
}
```
У цьому патерні браузер завантажує фрагмент `account-settings` під час простою. Коли користувач натискає, компонент рендериться миттєво, оскільки код уже доступний. Prefetching приймає ті самі типи тригерів, що й основна клауза `on`.
Поширений патерн для дашбордів: робити prefetch важких компонентів під час простою, водночас відкладаючи рендеринг до входу у viewport.
```typescript
// analytics.component.html
@defer (on viewport; prefetch on idle) {
} @placeholder (minimum 100ms) {
}
```
`minimum` у `@placeholder` запобігає стрибку макета (layout flash), коли користувач швидко прокручує, а відкладений компонент завантажується майже миттєво.
## @defer і рендеринг на стороні сервера (SSR)
На сервері блоки `@defer` за замовчуванням рендерять вміст `@placeholder`. Відкладений компонент ніколи не рендериться на сервері. Така поведінка є навмисною: завантаження фрагмента має сенс лише в контексті браузера.
Для контенту, критичного для SEO, це означає, що `@placeholder` має містити змістовний HTML, а не просто спінер:
```typescript
// blog-post.component.html
@defer (on viewport) {
} @placeholder {
Comments
Loading comments...
}
```
Пошукові системи індексують вміст заповнювача під час SSR. Описовий заповнювач гарантує, що сторінка залишається семантично повною.
## Інкрементальна гідратація з @defer
Angular 19 представив [інкрементальну гідратацію](https://angular.dev/guide/incremental-hydration) у режимі developer preview, а Angular 22 стабілізує її як готову до продакшену функцію. Інкрементальна гідратація розширює `@defer` тригером `hydrate`, який контролює, коли компонент, відрендерений на сервері, стає інтерактивним на клієнті.
```typescript
// product-page.component.html
@defer (hydrate on viewport) {
}
@defer (hydrate on interaction) {
}
```
На відміну від стандартного `@defer`, інкрементальна гідратація рендерить повний HTML компонента на сервері. Клієнт отримує повну розмітку, але пропускає гідратацію компонента до спрацювання тригера. Результат: браузер одразу малює повну сторінку, але виконання JavaScript відкладається.
Команда Angular повідомляє про стабільне покращення показників LCP на 40-50% при використанні інкрементальної гідратації на сторінках із великим обсягом контенту. Angular DevTools у версії 22 візуалізує стани гідратації (очікування, гідратовано, помилка) безпосередньо в інспекторі компонентів.
## Патерни з реальної практики та стратегія продуктивності
### Патерн 1: Важкий дашборд із кількома відкладеними панелями
```typescript
// dashboard.component.html
@defer (on viewport; prefetch on idle) {
} @placeholder {
}
@defer (on viewport; prefetch on idle) {
} @placeholder {
}
@defer (on interaction) {
} @placeholder {
}
```
Кожна панель завантажується незалежно. Панель експорту залишається незавантаженою, доки користувач явно її не запросить, що економить повне завантаження фрагмента для користувачів, які ніколи не експортують дані.
### Патерн 2: Умовне завантаження функцій із сигналами
```typescript
// editor.component.ts
export class EditorComponent {
user = inject(UserService).currentUser;
isPremium = computed(() => this.user()?.plan === 'premium');
}
// editor.component.html
@defer (when isPremium()) {
} @placeholder {
}
```
Користувачі безкоштовного тарифу ніколи не завантажують фрагмент AI-асистента. Банер апгрейду слугує одночасно заповнювачем і закликом до конверсії.
### Уникнення поширених пасток
Вкладення блоків `@defer` з однаковим тригером спричиняє одночасне завантаження фрагментів. Розподіляйте тригери між вкладеними блоками:
```typescript
// Avoid: both fire on idle simultaneously
@defer {
@defer {
}
}
// Better: outer on idle, inner on viewport
@defer (on idle) {
}
// Inside wrapper-component template:
@defer (on viewport) {
}
```
Ще одна пастка: використання `@defer` для компонентів, які вже перебувають на критичному шляху рендерингу. Відкладання контенту над лінією згину (above-the-fold) збільшує LCP, оскільки браузер має завантажити й виконати фрагмент перед малюванням. Зарезервуйте `@defer` для контенту нижче лінії згину або такого, що активується користувачем.
## @defer проти ледачого завантаження на основі роутера
Ледаче завантаження на основі роутера й `@defer` доповнюють одне одного. Ледаче завантаження роутера розділяє на рівні маршруту, відкладаючи цілі функціональні модулі. `@defer` розділяє всередині шаблону, відкладаючи окремі компоненти.
| Аспект | Ледаче завантаження роутера | @defer |
|--------|-------------------|--------|
| Гранулярність | Рівень маршруту | Рівень компонента |
| Тригер | Подія навігації | viewport, idle, interaction, hover, timer, умова |
| Поведінка в SSR | Повний рендеринг на сервері | Заповнювач на сервері |
| Потребує standalone | Ні (працює з NgModules) | Так (лише standalone) |
| Prefetching | `preloadingStrategy` | клауза `prefetch on` |
| Сценарій використання | Функціональні модулі, сторінки | Віджети, панелі, умовний UI |
Типовий застосунок використовує обидва підходи: ледаче завантаження роутера для функціональних областей верхнього рівня та `@defer` для важких компонентів усередині цих областей.
## Питання для співбесіди про Angular @defer
Технічні співбесіди дедалі частіше охоплюють `@defer`, оскільки він стає центральним елементом стратегії продуктивності Angular. Ось патерни, які часто зустрічаються у [питаннях для співбесіди з Angular](/technologies/angular/interview-questions/standalone-components).
**П: Що станеться, якщо компонент, який не є standalone, помістити всередину @defer?**
Компонент завантажується жадібно, незалежно від блоку `@defer`. Компілятор Angular не може виокремити компоненти, оголошені в NgModule, в окремі фрагменти. Помилка не викидається, але оптимізація мовчки не спрацьовує.
**П: Як @defer поводиться під час SSR?**
Сервер рендерить вміст `@placeholder`. Відкладений компонент ніколи не рендериться на стороні сервера. Гідратація відбувається на клієнті при спрацюванні тригера (або через `hydrate on` для інкрементальної гідратації).
**П: Чи можна використовувати @defer з OnPush change detection?**
Так. `@defer` є функцією рівня шаблону й працює з будь-якою стратегією виявлення змін. Відкладений компонент після завантаження дотримується власної конфігурації виявлення змін.
**П: Яка різниця між `on idle` та `on immediate`?**
`on idle` чекає, доки браузер завершить усі незавершені завдання через `requestIdleCallback`. `on immediate` спрацьовує одразу після завершення Angular першого проходу рендерингу, не чекаючи стану простою. `on immediate` корисний для компонентів, які мають завантажитися скоро, але не блокувати перше малювання.
Для ширшого набору матеріалів із підготовки до співбесіди з Angular дивіться [модуль change detection в Angular](/technologies/angular/interview-questions/change-detection) і [модуль сигналів Angular](/technologies/angular/interview-questions/angular-signals).
## Висновок
- `@defer` розділяє standalone-компоненти на окремі фрагменти, що завантажуються на вимогу, зменшуючи початковий розмір бандла без реструктуризації маршрутів
- Сім типів тригерів (`idle`, `viewport`, `interaction`, `hover`, `timer`, `immediate`, `when`) охоплюють кожну стратегію завантаження, від пасивної до керованої користувачем
- `prefetch on` відокремлює завантаження фрагмента від рендерингу компонента, усуваючи відчутну затримку в компонентах, що активуються користувачем
- Інкрементальна гідратація (`hydrate on`) рендерить повний HTML на сервері, відкладаючи виконання JavaScript на клієнт, що дає 40-50% покращення LCP на сторінках із великим обсягом контенту
- Вміст `@placeholder` рендериться під час SSR і має бути семантично змістовним заради SEO
- `@defer` доповнює ледаче завантаження на основі роутера: маршрути для розділення на рівні функцій, `@defer` для розділення на рівні компонентів у шаблонах
- Компоненти, які не є standalone, не можна відкласти, і вони мовчки завантажуються жадібно
---
Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack.
HTML version of this page: https://sharpskill.dev/uk/blog/angular/angular-defer-loading-declarative-lazy-loading-guide