# Angular @defer w 2026: deklaratywny lazy loading dla szybszych aplikacji
> Opanuj bloki @defer w Angularze do deklaratywnego lazy loadingu. Dogłębne omówienie wyzwalaczy, prefetchingu, hydratacji przyrostowej, zachowania w SSR i praktycznych wzorców wydajności.
- 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
---
Bloki `@defer` w Angularze rozwiązują problem, którego lazy loading oparty na routerze nigdy nie potrafił rozwiązać: ładowanie pojedynczych komponentów, dyrektyw i pipe'ów na żądanie bez przebudowywania aplikacji na osobne trasy. Wprowadzony w Angularze 17 i ustabilizowany do wersji 22, `@defer` zamienia to, co wcześniej wymagało dynamicznych importów, flag `*ngIf` i konfiguracji webpacka, w jeden deklaratywny blok szablonu.
> **Co robi @defer**
>
> `@defer` instruuje kompilator Angulara, aby podzielił opakowane komponenty na osobne fragmenty JavaScript (chunki), ładowane dopiero po spełnieniu warunku wyzwalacza. Przeglądarka pobiera mniej JavaScriptu na starcie, co poprawia Largest Contentful Paint (LCP) i Time to First Byte (TTFB) bez ręcznej konfiguracji code-splittingu.
## Jak @defer działa pod maską
Gdy kompilator Angulara napotyka blok `@defer`, wyodrębnia każdy samodzielny (standalone) komponent, dyrektywę i pipe znajdujące się wewnątrz niego do osobnego fragmentu. Główny pakiet jest dostarczany bez tych zależności. W czasie wykonania Angular ocenia warunek wyzwalacza i pobiera fragment za pomocą dynamicznego wywołania `import()`.
Blok obsługuje cztery podbloki, które kontrolują to, co widzi użytkownik podczas cyklu ładowania:
```typescript
// app.component.html
@defer (on viewport) {
} @placeholder {
} @loading (minimum 200ms) {
} @error {
Failed to load the dashboard. Please refresh.
}
```
`@placeholder` renderuje się przed uruchomieniem wyzwalacza. `@loading` pojawia się podczas pobierania fragmentu, z opcjonalnym czasem `minimum`, który zapobiega migotaniu (flicker). `@error` przechwytuje błędy sieci lub fragmentu. Parametr `minimum` w `@loading` zapobiega błyśnięciu spinnera, gdy fragment ładuje się szybko z pamięci podręcznej.
Jedno ograniczenie: każda zależność wewnątrz `@defer` musi być standalone. Komponenty niebędące standalone, zadeklarowane w `NgModule`, nie mogą być odroczone i zostaną załadowane zachłannie (eagerly) niezależnie od opakowania `@defer`.
## Typy wyzwalaczy: kontrola momentu ładowania komponentów
Angular udostępnia siedem wbudowanych wyzwalaczy, z których każdy odpowiada innej strategii ładowania. Wiele wyzwalaczy można łączyć średnikami i są one oceniane jako warunki 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) {
}
```
Wyzwalacz `on viewport` wewnętrznie korzysta z [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API). Wyzwalacz `on idle` deleguje do `requestIdleCallback`, co czyni go najbezpieczniejszym domyślnym wyborem dla treści poniżej linii zgięcia (below-the-fold). Wyzwalacz `on timer` przyjmuje czasy w milisekundach (`500ms`) lub sekundach (`3s`).
### Wyzwalacz `when` dla warunków reaktywnych
Poza wyzwalaczami opartymi na zdarzeniach, `when` przyjmuje dowolne wyrażenie logiczne, w tym odczyty sygnałów:
```typescript
// dashboard.component.ts
export class DashboardComponent {
showAdvanced = signal(false);
}
// dashboard.component.html
@defer (when showAdvanced()) {
} @placeholder {
}
```
Łączenie `on` i `when` jest dozwolone. Angular traktuje je jako OR: blok ładuje się, gdy spełniony jest którykolwiek z warunków.
## Prefetching: oddzielenie pobierania od wyświetlania
Prefetching oddziela moment pobierania fragmentu od momentu renderowania komponentu. Eliminuje to odczuwane opóźnienie, pobierając JavaScript zanim użytkownik go wyzwoli.
```typescript
// settings.component.html
@defer (on interaction; prefetch on idle) {
} @placeholder {
}
```
W tym wzorcu przeglądarka pobiera fragment `account-settings` w czasie bezczynności. Gdy użytkownik kliknie, komponent renderuje się natychmiast, ponieważ kod jest już dostępny. Prefetching przyjmuje te same typy wyzwalaczy co główna klauzula `on`.
Częsty wzorzec dla dashboardów: prefetch ciężkich komponentów w czasie bezczynności, przy jednoczesnym odroczeniu renderowania do momentu wejścia w viewport.
```typescript
// analytics.component.html
@defer (on viewport; prefetch on idle) {
} @placeholder (minimum 100ms) {
}
```
`minimum` w `@placeholder` zapobiega przeskokowi układu (layout flash), gdy użytkownik szybko przewija, a odroczony komponent ładuje się niemal natychmiast.
## @defer a renderowanie po stronie serwera (SSR)
Na serwerze bloki `@defer` domyślnie renderują zawartość `@placeholder`. Odroczony komponent nigdy nie jest renderowany po stronie serwera. To zachowanie jest celowe: pobieranie fragmentu ma sens wyłącznie w kontekście przeglądarki.
Dla treści krytycznej dla SEO oznacza to, że `@placeholder` musi zawierać sensowny HTML, a nie tylko spinner:
```typescript
// blog-post.component.html
@defer (on viewport) {
} @placeholder {
Comments
Loading comments...
}
```
Wyszukiwarki indeksują zawartość placeholdera podczas SSR. Opisowy placeholder zapewnia, że strona pozostaje kompletna semantycznie.
## Hydratacja przyrostowa z @defer
Angular 19 wprowadził [hydratację przyrostową](https://angular.dev/guide/incremental-hydration) w wersji developer preview, a Angular 22 stabilizuje ją jako funkcję gotową do produkcji. Hydratacja przyrostowa rozszerza `@defer` o wyzwalacz `hydrate`, który kontroluje, kiedy komponent renderowany na serwerze staje się interaktywny po stronie klienta.
```typescript
// product-page.component.html
@defer (hydrate on viewport) {
}
@defer (hydrate on interaction) {
}
```
W przeciwieństwie do standardowego `@defer`, hydratacja przyrostowa renderuje pełny HTML komponentu na serwerze. Klient otrzymuje kompletny markup, ale pomija hydratację komponentu aż do uruchomienia wyzwalacza. Efekt: przeglądarka natychmiast maluje pełną stronę, ale wykonanie JavaScriptu jest odroczone.
Zespół Angulara raportuje stałe poprawy wyników LCP rzędu 40-50% przy stosowaniu hydratacji przyrostowej na stronach o dużej ilości treści. Angular DevTools w wersji 22 wizualizuje stany hydratacji (oczekujący, zhydratowany, błąd) bezpośrednio w inspektorze komponentów.
## Wzorce z praktyki i strategia wydajności
### Wzorzec 1: Ciężki dashboard z wieloma odroczonymi panelami
```typescript
// dashboard.component.html
@defer (on viewport; prefetch on idle) {
} @placeholder {
}
@defer (on viewport; prefetch on idle) {
} @placeholder {
}
@defer (on interaction) {
} @placeholder {
}
```
Każdy panel ładuje się niezależnie. Panel eksportu pozostaje niezaładowany, dopóki użytkownik wyraźnie go nie zażąda, co oszczędza pełne pobranie fragmentu dla użytkowników, którzy nigdy nie eksportują danych.
### Wzorzec 2: Warunkowe ładowanie funkcji z sygnałami
```typescript
// editor.component.ts
export class EditorComponent {
user = inject(UserService).currentUser;
isPremium = computed(() => this.user()?.plan === 'premium');
}
// editor.component.html
@defer (when isPremium()) {
} @placeholder {
}
```
Użytkownicy z darmowym planem nigdy nie pobierają fragmentu asystenta AI. Baner z propozycją upgrade'u pełni rolę zarówno placeholdera, jak i zachęty do konwersji.
### Unikanie typowych pułapek
Zagnieżdżanie bloków `@defer` z tym samym wyzwalaczem powoduje równoczesne pobieranie fragmentów. Rozłóż wyzwalacze pomiędzy zagnieżdżone bloki:
```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) {
}
```
Kolejna pułapka: używanie `@defer` dla komponentów znajdujących się już na krytycznej ścieżce renderowania. Odraczanie treści powyżej linii zgięcia (above-the-fold) zwiększa LCP, ponieważ przeglądarka musi pobrać i wykonać fragment przed namalowaniem. Zarezerwuj `@defer` dla treści poniżej linii zgięcia lub wyzwalanej przez użytkownika.
## @defer kontra lazy loading oparty na routerze
Lazy loading oparty na routerze i `@defer` uzupełniają się nawzajem. Lazy loading routera dzieli na poziomie trasy, odraczając całe moduły funkcjonalne. `@defer` dzieli wewnątrz szablonu, odraczając pojedyncze komponenty.
| Aspekt | Lazy loading routera | @defer |
|--------|-------------------|--------|
| Granularność | Poziom trasy | Poziom komponentu |
| Wyzwalacz | Zdarzenie nawigacji | viewport, idle, interaction, hover, timer, warunek |
| Zachowanie w SSR | Pełny render na serwerze | Placeholder na serwerze |
| Wymaga standalone | Nie (działa z NgModules) | Tak (tylko standalone) |
| Prefetching | `preloadingStrategy` | klauzula `prefetch on` |
| Zastosowanie | Moduły funkcjonalne, strony | Widżety, panele, warunkowy UI |
Typowa aplikacja używa obu: lazy loadingu routera dla obszarów funkcjonalnych najwyższego poziomu oraz `@defer` dla ciężkich komponentów w obrębie tych obszarów.
## Pytania rekrutacyjne dotyczące Angular @defer
Rozmowy techniczne coraz częściej obejmują `@defer`, w miarę jak staje się on centralnym elementem strategii wydajności Angulara. Oto wzorce, które często pojawiają się w [pytaniach rekrutacyjnych z Angulara](/technologies/angular/interview-questions/standalone-components).
**P: Co się stanie, jeśli komponent niebędący standalone zostanie umieszczony wewnątrz @defer?**
Komponent ładuje się zachłannie, niezależnie od bloku `@defer`. Kompilator Angulara nie może wyodrębnić komponentów zadeklarowanych w NgModule do osobnych fragmentów. Nie jest zgłaszany żaden błąd, ale optymalizacja po cichu zawodzi.
**P: Jak @defer zachowuje się podczas SSR?**
Serwer renderuje zawartość `@placeholder`. Odroczony komponent nigdy nie jest renderowany po stronie serwera. Hydratacja następuje po stronie klienta po uruchomieniu wyzwalacza (lub przez `hydrate on` w przypadku hydratacji przyrostowej).
**P: Czy @defer można używać z OnPush change detection?**
Tak. `@defer` jest funkcją na poziomie szablonu i działa z dowolną strategią wykrywania zmian. Odroczony komponent po załadowaniu stosuje własną konfigurację wykrywania zmian.
**P: Jaka jest różnica między `on idle` a `on immediate`?**
`on idle` czeka, aż przeglądarka zakończy wszystkie oczekujące zadania poprzez `requestIdleCallback`. `on immediate` uruchamia się tuż po zakończeniu przez Angular pierwszego przebiegu renderowania, bez czekania na stan bezczynności. `on immediate` jest przydatny dla komponentów, które powinny załadować się szybko, ale nie blokować pierwszego malowania.
Aby uzyskać szerszy zestaw materiałów do przygotowania na rozmowę z Angulara, zobacz [moduł change detection w Angularze](/technologies/angular/interview-questions/change-detection) oraz [moduł sygnałów Angulara](/technologies/angular/interview-questions/angular-signals).
## Podsumowanie
- `@defer` dzieli komponenty standalone na osobne fragmenty ładowane na żądanie, redukując początkowy rozmiar pakietu bez przebudowy tras
- Siedem typów wyzwalaczy (`idle`, `viewport`, `interaction`, `hover`, `timer`, `immediate`, `when`) pokrywa każdą strategię ładowania, od pasywnej po sterowaną przez użytkownika
- `prefetch on` oddziela pobieranie fragmentu od renderowania komponentu, eliminując odczuwane opóźnienie w komponentach wyzwalanych przez użytkownika
- Hydratacja przyrostowa (`hydrate on`) renderuje pełny HTML na serwerze, odraczając wykonanie JavaScriptu do klienta, co daje 40-50% poprawy LCP na stronach o dużej ilości treści
- Zawartość `@placeholder` renderuje się podczas SSR i musi być sensowna semantycznie ze względu na SEO
- `@defer` uzupełnia lazy loading oparty na routerze: trasy dla podziału na poziomie funkcji, `@defer` dla podziału na poziomie komponentów w szablonach
- Komponenty niebędące standalone nie mogą być odroczone i po cichu ładują się zachłannie
---
Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack.
HTML version of this page: https://sharpskill.dev/pl/blog/angular/angular-defer-loading-declarative-lazy-loading-guide