Angular @defer у 2026: декларативне ледаче завантаження для швидших застосунків
Опануйте блоки @defer в Angular для декларативного ледачого завантаження. Глибокий розбір тригерів, prefetching, інкрементальної гідратації, поведінки в SSR і практичних патернів продуктивності.

Блоки @defer в Angular вирішують проблему, яку ледаче завантаження на основі роутера ніколи не могло вирішити: завантаження окремих компонентів, директив і пайпів на вимогу без реструктуризації застосунку на окремі маршрути. Представлений в Angular 17 і стабілізований у версії 22, @defer перетворює те, що раніше вимагало динамічних імпортів, прапорців *ngIf і налаштування webpack, на єдиний декларативний блок шаблону.
@defer вказує компілятору Angular розділити обгорнуті компоненти на окремі фрагменти JavaScript (chunks), які завантажуються лише після спрацювання умови тригера. Браузер завантажує менше JavaScript на старті, що покращує Largest Contentful Paint (LCP) і Time to First Byte (TTFB) без ручного налаштування code-splitting.
Як @defer працює під капотом
Коли компілятор Angular зустрічає блок @defer, він виокремлює кожен самостійний (standalone) компонент, директиву та пайп усередині нього в окремий фрагмент. Основний бандл постачається без цих залежностей. Під час виконання Angular оцінює умову тригера й отримує фрагмент через динамічний виклик import().
Блок підтримує чотири підблоки, які контролюють те, що бачить користувач протягом життєвого циклу завантаження:
@defer (on viewport) {
<analytics-dashboard />
} @placeholder {
<div class="h-64 bg-muted animate-pulse"></div>
} @loading (minimum 200ms) {
<loading-spinner />
} @error {
<p>Failed to load the dashboard. Please refresh.</p>
}@placeholder рендериться до спрацювання тригера. @loading зʼявляється під час завантаження фрагмента, з опціональною тривалістю minimum, щоб запобігти мерехтінню (flicker). @error перехоплює мережеві помилки або помилки фрагмента. Параметр minimum у @loading запобігає спалаху спінера, коли фрагмент швидко завантажується з кешу.
Одне обмеження: кожна залежність усередині @defer має бути standalone. Компоненти, що не є standalone та оголошені в NgModule, не можна відкласти, і вони завантажаться жадібно (eagerly) незалежно від обгортки @defer.
Типи тригерів: контроль моменту завантаження компонентів
Angular надає сім вбудованих тригерів, кожен з яких відповідає за іншу стратегію завантаження. Кілька тригерів можна обʼєднати крапками з комою, і вони оцінюються як умови OR.
// Loads when the browser goes idle (default)
@defer {
<recommendation-engine />
}
// Loads when the element enters the viewport
@defer (on viewport) {
<customer-reviews [productId]="product.id" />
}
// Loads on click or keydown
@defer (on interaction) {
<product-configurator />
} @placeholder {
<button>Configure this product</button>
}
// Loads on mouseenter or focusin
@defer (on hover) {
<quick-preview />
}
// Loads after 3 seconds
@defer (on timer(3s)) {
<chat-widget />
}
// Loads immediately after initial render
@defer (on immediate) {
<notification-center />
}Тригер on viewport внутрішньо використовує Intersection Observer API. Тригер on idle делегує до requestIdleCallback, що робить його найбезпечнішим типовим вибором для контенту нижче лінії згину (below-the-fold). Тригер on timer приймає тривалість у мілісекундах (500ms) або секундах (3s).
Тригер when для реактивних умов
Окрім тригерів на основі подій, when приймає будь-який булевий вираз, включно зі зчитуванням сигналів:
export class DashboardComponent {
showAdvanced = signal(false);
}
// dashboard.component.html
@defer (when showAdvanced()) {
<advanced-analytics />
} @placeholder {
<button (click)="showAdvanced.set(true)">Show advanced analytics</button>
}Поєднання on і when є допустимим. Angular трактує їх як OR: блок завантажується, коли виконано будь-яку з умов.
Prefetching: відокремлення завантаження від відображення
Prefetching відокремлює момент завантаження фрагмента від моменту рендерингу компонента. Це усуває відчутну затримку, отримуючи JavaScript ще до того, як користувач його активує.
@defer (on interaction; prefetch on idle) {
<account-settings />
} @placeholder {
<button>Open settings</button>
}У цьому патерні браузер завантажує фрагмент account-settings під час простою. Коли користувач натискає, компонент рендериться миттєво, оскільки код уже доступний. Prefetching приймає ті самі типи тригерів, що й основна клауза on.
Поширений патерн для дашбордів: робити prefetch важких компонентів під час простою, водночас відкладаючи рендеринг до входу у viewport.
@defer (on viewport; prefetch on idle) {
<chart-widget [data]="salesData()" />
} @placeholder (minimum 100ms) {
<div class="h-48 bg-muted rounded-none"></div>
}minimum у @placeholder запобігає стрибку макета (layout flash), коли користувач швидко прокручує, а відкладений компонент завантажується майже миттєво.
Готовий до співбесід з Angular?
Практикуйся з нашими інтерактивними симуляторами, flashcards та технічними тестами.
@defer і рендеринг на стороні сервера (SSR)
На сервері блоки @defer за замовчуванням рендерять вміст @placeholder. Відкладений компонент ніколи не рендериться на сервері. Така поведінка є навмисною: завантаження фрагмента має сенс лише в контексті браузера.
Для контенту, критичного для SEO, це означає, що @placeholder має містити змістовний HTML, а не просто спінер:
@defer (on viewport) {
<comment-section [postId]="post.id" />
} @placeholder {
<section aria-label="Comments">
<h2>Comments</h2>
<p>Loading comments...</p>
</section>
}Пошукові системи індексують вміст заповнювача під час SSR. Описовий заповнювач гарантує, що сторінка залишається семантично повною.
Інкрементальна гідратація з @defer
Angular 19 представив інкрементальну гідратацію у режимі developer preview, а Angular 22 стабілізує її як готову до продакшену функцію. Інкрементальна гідратація розширює @defer тригером hydrate, який контролює, коли компонент, відрендерений на сервері, стає інтерактивним на клієнті.
@defer (hydrate on viewport) {
<product-gallery [images]="product.images" />
}
@defer (hydrate on interaction) {
<product-reviews [productId]="product.id" />
}На відміну від стандартного @defer, інкрементальна гідратація рендерить повний HTML компонента на сервері. Клієнт отримує повну розмітку, але пропускає гідратацію компонента до спрацювання тригера. Результат: браузер одразу малює повну сторінку, але виконання JavaScript відкладається.
Команда Angular повідомляє про стабільне покращення показників LCP на 40-50% при використанні інкрементальної гідратації на сторінках із великим обсягом контенту. Angular DevTools у версії 22 візуалізує стани гідратації (очікування, гідратовано, помилка) безпосередньо в інспекторі компонентів.
Патерни з реальної практики та стратегія продуктивності
Патерн 1: Важкий дашборд із кількома відкладеними панелями
<div class="grid grid-cols-2 gap-4">
@defer (on viewport; prefetch on idle) {
<sales-chart />
} @placeholder {
<skeleton-card height="300px" />
}
@defer (on viewport; prefetch on idle) {
<user-activity-feed />
} @placeholder {
<skeleton-card height="300px" />
}
@defer (on interaction) {
<export-panel />
} @placeholder {
<button>Export data</button>
}
</div>Кожна панель завантажується незалежно. Панель експорту залишається незавантаженою, доки користувач явно її не запросить, що економить повне завантаження фрагмента для користувачів, які ніколи не експортують дані.
Патерн 2: Умовне завантаження функцій із сигналами
export class EditorComponent {
user = inject(UserService).currentUser;
isPremium = computed(() => this.user()?.plan === 'premium');
}
// editor.component.html
@defer (when isPremium()) {
<ai-assistant />
} @placeholder {
<upgrade-banner />
}Користувачі безкоштовного тарифу ніколи не завантажують фрагмент AI-асистента. Банер апгрейду слугує одночасно заповнювачем і закликом до конверсії.
Уникнення поширених пасток
Вкладення блоків @defer з однаковим тригером спричиняє одночасне завантаження фрагментів. Розподіляйте тригери між вкладеними блоками:
// Avoid: both fire on idle simultaneously
@defer {
@defer {
<nested-heavy-component />
}
}
// Better: outer on idle, inner on viewport
@defer (on idle) {
<wrapper-component />
}
// Inside wrapper-component template:
@defer (on viewport) {
<nested-heavy-component />
}Ще одна пастка: використання @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.
П: Що станеться, якщо компонент, який не є 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 і модуль сигналів Angular.
Починай практикувати!
Перевір свої знання з нашими симуляторами співбесід та технічними тестами.
Висновок
@deferрозділяє standalone-компоненти на окремі фрагменти, що завантажуються на вимогу, зменшуючи початковий розмір бандла без реструктуризації маршрутів- Сім типів тригерів (
idle,viewport,interaction,hover,timer,immediate,when) охоплюють кожну стратегію завантаження, від пасивної до керованої користувачем prefetch onвідокремлює завантаження фрагмента від рендерингу компонента, усуваючи відчутну затримку в компонентах, що активуються користувачем- Інкрементальна гідратація (
hydrate on) рендерить повний HTML на сервері, відкладаючи виконання JavaScript на клієнт, що дає 40-50% покращення LCP на сторінках із великим обсягом контенту - Вміст
@placeholderрендериться під час SSR і має бути семантично змістовним заради SEO @deferдоповнює ледаче завантаження на основі роутера: маршрути для розділення на рівні функцій,@deferдля розділення на рівні компонентів у шаблонах- Компоненти, які не є standalone, не можна відкласти, і вони мовчки завантажуються жадібно
Починай практикувати!
Перевір свої знання з нашими симуляторами співбесід та технічними тестами.
Теги
Поділитися
Пов'язані статті

Питання співбесіди Angular 19: Signals, SSR і обов'язкові концепції
Найпоширеніші питання співбесіди з Angular 19: Signals, інкрементальна гідратація, zoneless change detection і нові реактивні API з прикладами коду та очікуваними відповідями.

Angular 19 Zoneless: Продуктивність та Виявлення Змін Без Zone.js
Повний посібник з Angular zoneless change detection: видалення Zone.js, перехід на сигнали, налаштування provideZonelessChangeDetection, оптимізація SSR, міграція існуючих застосунків та підготовка до технічних співбесід з Angular.

Angular 20 Resource API, httpResource Ñа пиÑÐ°Ð½Ð½Ñ Ð´Ð»Ñ ÑÐµÑ Ð½ÑÑÐ½Ð¸Ñ ÑпÑвбеÑÑд
ÐеÑалÑний поÑÑбник з Resource API в Angular 20: resource(), rxResource() Ñа httpResource() Ð´Ð»Ñ ÑеакÑивного оÑÑÐ¸Ð¼Ð°Ð½Ð½Ñ Ð´Ð°Ð½Ð¸Ñ . ÐалÑдаÑÑÑ Zod, ÑÑÐ´ÐºÐ¾Ð²Ñ ÑÑаÑÑÑи, мÑгÑаÑÑÑ Ð· HttpClient Ñа акÑÑалÑÐ½Ñ Ð¿Ð¸ÑÐ°Ð½Ð½Ñ Ð´Ð»Ñ ÑÐµÑ Ð½ÑÑÐ½Ð¸Ñ ÑпÑвбеÑÑд Angular Ñ 2026 ÑоÑÑ.