Angular @defer nel 2026: Lazy Loading Dichiarativo e Domande da Colloquio Tecnico
Guida approfondita ai blocchi @defer di Angular: lazy loading dichiarativo con trigger viewport, interaction e timer. Prefetching, SSR, idratazione incrementale e domande da colloquio tecnico.

I blocchi @defer di Angular risolvono un problema che il lazy loading basato su router non ha mai potuto affrontare: il caricamento on-demand di singoli componenti, direttive e pipe senza la necessità di ristrutturare l'applicazione in route separate. Introdotti in Angular 17 e stabilizzati nel corso delle versioni successive fino ad Angular 22, i blocchi @defer trasformano quello che in precedenza richiedeva import dinamici, flag *ngIf e configurazioni webpack in un singolo costrutto dichiarativo a livello di template.
@defer istruisce il compilatore Angular a separare i componenti racchiusi nel blocco in chunk JavaScript distinti, caricati soltanto quando una condizione trigger si attiva. Il browser scarica meno JavaScript inizialmente, migliorando il Largest Contentful Paint (LCP) e il Time to First Byte (TTFB) senza configurazioni manuali di code-splitting.
Come funziona @defer internamente
Quando il compilatore Angular incontra un blocco @defer, estrae ogni componente standalone, direttiva e pipe al suo interno in un chunk separato. Il bundle principale viene distribuito senza queste dipendenze. A runtime, Angular valuta la condizione trigger ed effettua il fetch del chunk tramite una chiamata dinamica import().
Il blocco supporta quattro sotto-blocchi che controllano ciò che l'utente visualizza durante il ciclo di vita del caricamento:
@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 viene renderizzato prima che il trigger si attivi. @loading appare durante il download del chunk, con un parametro opzionale minimum per prevenire il flickering. @error intercetta errori di rete o errori di caricamento del chunk. Il parametro minimum su @loading evita un flash dello spinner quando il chunk viene caricato rapidamente dalla cache.
Un vincolo fondamentale: ogni dipendenza all'interno di @defer deve essere standalone. I componenti non-standalone dichiarati in un NgModule non possono essere differiti e vengono caricati eagerly indipendentemente dal wrapper @defer.
Tipi di trigger: controllare quando i componenti vengono caricati
Angular fornisce sette trigger integrati, ciascuno orientato a una diversa strategia di caricamento. Più trigger possono essere combinati con il punto e virgola e vengono valutati come condizioni 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 />
}Il trigger on viewport utilizza internamente l'Intersection Observer API. Il trigger on idle delega a requestIdleCallback, risultando il default più sicuro per contenuti below-the-fold. Il trigger on timer accetta durate in millisecondi (500ms) o secondi (3s).
Il trigger when per condizioni reattive
Oltre ai trigger basati su eventi, when accetta qualsiasi espressione booleana, incluse le letture di signal:
export class DashboardComponent {
showAdvanced = signal(false);
}
// dashboard.component.html
@defer (when showAdvanced()) {
<advanced-analytics />
} @placeholder {
<button (click)="showAdvanced.set(true)">Show advanced analytics</button>
}Combinare on e when è perfettamente valido. Angular li tratta come condizioni OR: il blocco viene caricato quando una delle due condizioni si verifica.
Prefetching: separare il download dalla visualizzazione
Il prefetching disaccoppia il momento del download del chunk dal momento in cui il componente viene renderizzato. Questo elimina la latenza percepita scaricando il JavaScript prima che l'utente attivi il trigger.
@defer (on interaction; prefetch on idle) {
<account-settings />
} @placeholder {
<button>Open settings</button>
}In questo pattern, il browser scarica il chunk di account-settings durante i momenti di inattività. Quando l'utente clicca, il componente viene renderizzato istantaneamente perché il codice è già disponibile. Il prefetching accetta gli stessi tipi di trigger della clausola principale on.
Un pattern comune per le dashboard: eseguire il prefetch di componenti pesanti durante l'idle e differire il rendering all'ingresso nel viewport.
@defer (on viewport; prefetch on idle) {
<chart-widget [data]="salesData()" />
} @placeholder (minimum 100ms) {
<div class="h-48 bg-muted rounded-none"></div>
}Il parametro minimum su @placeholder previene un flash di layout quando l'utente scorre rapidamente e il componente differito viene caricato quasi istantaneamente.
Pronto a superare i tuoi colloqui su Angular?
Pratica con i nostri simulatori interattivi, flashcards e test tecnici.
@defer e Server-Side Rendering
Sul server, i blocchi @defer renderizzano il contenuto di @placeholder per impostazione predefinita. Il componente differito non viene mai renderizzato lato server. Questo comportamento è intenzionale: il download del chunk ha senso esclusivamente in un contesto browser.
Per i contenuti critici ai fini della SEO, ciò significa che il @placeholder deve contenere HTML semanticamente significativo, non soltanto uno spinner:
@defer (on viewport) {
<comment-section [postId]="post.id" />
} @placeholder {
<section aria-label="Comments">
<h2>Comments</h2>
<p>Loading comments...</p>
</section>
}I motori di ricerca indicizzano il contenuto del placeholder durante il rendering SSR. Un placeholder descrittivo garantisce che la pagina rimanga semanticamente completa.
Idratazione incrementale con @defer
Angular 19 ha introdotto l'idratazione incrementale in developer preview, e Angular 22 la stabilizza come funzionalità pronta per la produzione. L'idratazione incrementale estende @defer con un trigger hydrate che controlla quando un componente renderizzato lato server diventa interattivo sul client.
@defer (hydrate on viewport) {
<product-gallery [images]="product.images" />
}
@defer (hydrate on interaction) {
<product-reviews [productId]="product.id" />
}A differenza del @defer standard, l'idratazione incrementale renderizza l'HTML completo del componente sul server. Il client riceve il markup completo ma posticipa l'idratazione del componente fino all'attivazione del trigger. Il risultato: il browser visualizza la pagina completa immediatamente, ma l'esecuzione del JavaScript viene differita.
Il team Angular riporta miglioramenti costanti del 40-50% nei punteggi LCP quando si utilizza l'idratazione incrementale su pagine ricche di contenuti. Angular DevTools nella versione 22 visualizza gli stati di idratazione (pending, hydrated, error) direttamente nell'inspector dei componenti.
Pattern reali e strategia di ottimizzazione delle performance
Pattern 1: Dashboard pesante con pannelli differiti multipli
<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>Ogni pannello viene caricato in modo indipendente. Il pannello di esportazione rimane scaricato fino a quando l'utente non lo richiede esplicitamente, risparmiando il download di un intero chunk per gli utenti che non esportano mai dati.
Pattern 2: Caricamento condizionale di funzionalità con signal
export class EditorComponent {
user = inject(UserService).currentUser;
isPremium = computed(() => this.user()?.plan === 'premium');
}
// editor.component.html
@defer (when isPremium()) {
<ai-assistant />
} @placeholder {
<upgrade-banner />
}Gli utenti del piano gratuito non scaricano mai il chunk dell'assistente AI. Il banner di upgrade funge sia da placeholder che da elemento di conversione.
Evitare le insidie più comuni
Annidare blocchi @defer con lo stesso trigger causa download simultanei dei chunk. I trigger devono essere sfalsati tra blocchi annidati:
// 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 />
}Un'altra insidia frequente: utilizzare @defer per componenti che si trovano già nel percorso critico di rendering. Differire contenuti above-the-fold aumenta l'LCP perché il browser deve scaricare ed eseguire il chunk prima di poter dipingere la pagina. Il consiglio è riservare @defer per contenuti below-the-fold o attivati dall'utente.
@defer vs Lazy Loading basato su Router
Il lazy loading basato su router e @defer sono strumenti complementari. Il lazy loading del router suddivide a livello di route, differendo interi feature module. @defer suddivide all'interno di un template, differendo singoli componenti.
| Aspetto | Router Lazy Loading | @defer |
|---------|-------------------|--------|
| Granularità | Livello di route | Livello di componente |
| Trigger | Evento di navigazione | viewport, idle, interaction, hover, timer, condizione |
| Comportamento SSR | Rendering server completo | Placeholder sul server |
| Richiede standalone | No (funziona con NgModules) | Sì (solo standalone) |
| Prefetching | preloadingStrategy | clausola prefetch on |
| Caso d'uso | Feature module, pagine | Widget, pannelli, UI condizionale |
Un'applicazione tipica utilizza entrambi gli approcci: il lazy loading del router per le aree funzionali di primo livello e @defer per i componenti pesanti all'interno di quelle aree.
Domande da colloquio tecnico su Angular @defer
I colloqui tecnici includono sempre più frequentemente domande su @defer, dato il suo ruolo centrale nella strategia di ottimizzazione delle performance Angular. Di seguito i pattern che compaiono regolarmente nelle domande di colloquio Angular.
D: Che cosa succede se un componente non-standalone viene inserito all'interno di @defer?
Il componente viene caricato eagerly indipendentemente dal blocco @defer. Il compilatore Angular non può estrarre componenti dichiarati in un NgModule in chunk separati. Non viene generato alcun errore, ma l'ottimizzazione fallisce silenziosamente.
D: Come si comporta @defer durante il Server-Side Rendering?
Il server renderizza il contenuto di @placeholder. Il componente differito non viene mai renderizzato lato server. L'idratazione avviene sul client quando il trigger si attiva (oppure tramite hydrate on per l'idratazione incrementale).
D: È possibile utilizzare @defer con la strategia di change detection OnPush?
Sì. @defer è una funzionalità a livello di template e funziona con qualsiasi strategia di change detection. Il componente differito segue la propria configurazione di change detection una volta caricato. Per un approfondimento sul change detection, consultare il modulo dedicato su Angular change detection.
D: Qual è la differenza tra on idle e on immediate?
on idle attende che il browser completi tutto il lavoro pendente tramite requestIdleCallback. on immediate si attiva subito dopo il completamento del render iniziale da parte di Angular, senza attendere lo stato di idle. on immediate risulta utile per componenti che devono essere caricati presto ma senza bloccare il first paint.
D: Come interagiscono on e when quando vengono combinati in un singolo blocco @defer?
Angular li tratta come condizioni OR. Il blocco viene caricato quando una qualsiasi delle condizioni specificate si verifica per prima. Questo consente pattern flessibili dove un componente può essere caricato sia in risposta a un evento del browser che a un cambiamento di stato nell'applicazione.
D: Come si può garantire che il contenuto differito non impatti negativamente sulla SEO?
Durante il rendering SSR, il server restituisce esclusivamente il contenuto di @placeholder. Per contenuti rilevanti ai fini SEO, il placeholder deve contenere HTML semanticamente significativo che i motori di ricerca possano indicizzare. Utilizzare tag semantici come <section>, <h2> e testo descrittivo nel placeholder garantisce la completezza semantica della pagina.
Per una preparazione completa ai colloqui Angular, consultare anche il modulo sugli Angular signals e quello sul change detection.
Inizia a praticare!
Metti alla prova le tue conoscenze con i nostri simulatori di colloquio e test tecnici.
Conclusione
@defersepara i componenti standalone in chunk distinti caricati on-demand, riducendo la dimensione del bundle iniziale senza ristrutturazione delle route- Sette tipi di trigger (
idle,viewport,interaction,hover,timer,immediate,when) coprono ogni strategia di caricamento, da quella passiva a quella guidata dall'utente prefetch ondisaccoppia il download del chunk dal rendering del componente, eliminando la latenza percepita sui componenti attivati dall'utente- L'idratazione incrementale (
hydrate on) renderizza l'HTML completo sul server posticipando l'esecuzione JavaScript al client, con miglioramenti del 40-50% nei punteggi LCP su pagine ricche di contenuti - Il contenuto di
@placeholderviene renderizzato durante l'SSR e deve essere semanticamente significativo ai fini della SEO @defercomplementa il lazy loading basato su router: le route per la suddivisione a livello di feature,@deferper la suddivisione a livello di componente all'interno dei template- I componenti non-standalone non possono essere differiti e vengono caricati eagerly in modo silenzioso
Inizia a praticare!
Metti alla prova le tue conoscenze con i nostri simulatori di colloquio e test tecnici.
Tag
Condividi
Articoli correlati

Domande di colloquio Angular 19: Signals, SSR e concetti imprescindibili
Le domande di colloquio Angular 19 più frequenti: Signals, idratazione incrementale, change detection senza Zone.js e nuove API reattive con esempi di codice e risposte attese.

Angular 19 Zoneless: Performance e Change Detection senza Zone.js
Guida tecnica approfondita alla Zoneless Change Detection in Angular 19 e 20. Funzionamento della reattività basata su Signals, attivazione di provideZonelessChangeDetection, insidie nella migrazione con setTimeout e Reactive Forms, SSR senza Zone.js e benchmark prestazionali.

Angular 20 nel 2026: Resource API, httpResource e domande da colloquio
Angular 20 introduce la Resource API e httpResource come alternative signal-based alle sottoscrizioni manuali di HttpClient. Questa guida copre tutte e tre le varianti Resource, la validazione con Zod e le domande più frequenti nei colloqui tecnici.