Angular @defer em 2026: Lazy Loading Declarativo e Entrevistas
Domine os blocos @defer do Angular para lazy loading declarativo no nível de componente. Guia completo sobre gatilhos, prefetching, hidratação incremental, comportamento SSR e padrões de performance para aplicações reais.

O lazy loading baseado no roteador sempre foi a principal ferramenta de otimizacao de performance no Angular, mas possui uma limitacao estrutural: opera exclusivamente no nivel de rota. Para carregar um widget pesado condicionalmente dentro de uma pagina, era necessario recorrer a dynamic imports manuais, flags com *ngIf e configuracoes especificas de bundler. O bloco @defer, introduzido no Angular 17 e estabilizado ao longo das versoes ate o Angular 22, elimina essa complexidade ao oferecer lazy loading declarativo diretamente no template.
Com @defer, o desenvolvedor define no proprio HTML quais componentes devem ser carregados sob demanda e em quais condicoes. O compilador do Angular cuida de todo o restante: separacao de chunks, imports dinamicos e gerenciamento do ciclo de vida do carregamento. O resultado e uma reducao significativa do bundle inicial sem necessidade de reestruturar a aplicacao em rotas separadas.
O @defer instrui o compilador do Angular a separar os componentes envolvidos em chunks JavaScript independentes, carregados apenas quando uma condicao de gatilho e ativada. O navegador baixa menos JavaScript na carga inicial, melhorando o Largest Contentful Paint (LCP) e o Time to First Byte (TTFB) sem configuracao manual de code-splitting.
Como o @defer funciona por baixo dos panos
Quando o compilador do Angular encontra um bloco @defer, ele extrai todos os componentes standalone, diretivas e pipes contidos nele para um chunk separado. O bundle principal e entregue ao navegador sem essas dependencias. Em tempo de execucao, o Angular avalia a condicao do gatilho e busca o chunk via uma chamada dinamica de import().
O bloco suporta quatro sub-blocos que controlam o que o usuario visualiza durante o ciclo de vida do carregamento:
@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>
}O @placeholder renderiza antes do gatilho ser acionado. O @loading aparece enquanto o chunk esta sendo baixado, com um parametro opcional minimum que evita flickers visuais. O @error captura falhas de rede ou erros no carregamento do chunk. O parametro minimum no @loading impede aquele flash de spinner quando o chunk carrega rapidamente a partir do cache.
Ha uma restricao fundamental: todas as dependencias dentro de @defer precisam ser standalone. Componentes declarados em um NgModule tradicional nao podem ser deferidos e serao carregados eagerly, independentemente do wrapper @defer. Nenhum erro e lancado nesse caso, mas a otimizacao simplesmente nao se aplica.
Tipos de gatilhos: controlando quando os componentes carregam
O Angular disponibiliza sete gatilhos nativos, cada um voltado para uma estrategia de carregamento diferente. Varios gatilhos podem ser combinados com ponto e virgula, sendo avaliados como condicoes 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 />
}O gatilho on viewport utiliza a Intersection Observer API internamente, detectando quando o placeholder entra na area visivel do navegador. O on idle delega ao requestIdleCallback, tornando-o a escolha mais segura para conteudo abaixo da dobra. O on timer aceita duracoes em milissegundos (500ms) ou segundos (3s).
O gatilho on interaction responde a eventos de clique ou keydown, tornando-o ideal para paineis que devem carregar apenas quando o usuario manifesta intencao de uso. O on hover responde a mouseenter e focusin, util para pre-visualizacoes rapidas em interfaces desktop. O on immediate dispara logo apos o render inicial, sem aguardar o estado idle do navegador, servindo para componentes que precisam carregar cedo mas nao devem bloquear a primeira pintura.
O gatilho when para condicoes reativas
Alem dos gatilhos baseados em eventos, o when aceita qualquer expressao booleana, incluindo leituras de signals:
export class DashboardComponent {
showAdvanced = signal(false);
}
// dashboard.component.html
@defer (when showAdvanced()) {
<advanced-analytics />
} @placeholder {
<button (click)="showAdvanced.set(true)">Show advanced analytics</button>
}Combinar on e when na mesma declaracao e valido. O Angular trata ambos como OR: o bloco carrega quando qualquer uma das condicoes for satisfeita. Esse padrao e particularmente poderoso em cenarios onde funcionalidades premium devem carregar apenas para usuarios autorizados, mantendo o chunk fora do bundle de usuarios do plano gratuito. Para aprofundamento no sistema reativo do Angular, o modulo de Angular signals aborda os conceitos fundamentais.
Prefetching: separando o download da exibicao
O prefetching desacopla o momento em que o chunk e baixado do momento em que o componente e renderizado. Essa separacao elimina a latencia percebida pelo usuario, buscando o JavaScript antes que a acao de exibicao seja disparada.
@defer (on interaction; prefetch on idle) {
<account-settings />
} @placeholder {
<button>Open settings</button>
}Nesse padrao, o navegador baixa o chunk de account-settings durante o tempo ocioso. Quando o usuario clica, o componente renderiza instantaneamente porque o codigo ja esta disponivel. O prefetching aceita os mesmos tipos de gatilho da clausula principal on.
Um padrao recorrente em dashboards: prefetch de componentes pesados no idle enquanto o render fica condicionado a entrada no viewport.
@defer (on viewport; prefetch on idle) {
<chart-widget [data]="salesData()" />
} @placeholder (minimum 100ms) {
<div class="h-48 bg-muted rounded-none"></div>
}O minimum no @placeholder previne um flash de layout quando o usuario faz scroll rapido e o componente deferido carrega quase instantaneamente.
Pronto para mandar bem nas entrevistas de Angular?
Pratique com nossos simuladores interativos, flashcards e testes tecnicos.
@defer e renderizacao no lado do servidor (SSR)
No servidor, os blocos @defer renderizam o conteudo do @placeholder por padrao. O componente deferido nunca e renderizado no lado do servidor. Esse comportamento e intencional: o download de chunks so faz sentido no contexto do navegador.
Para conteudo critico de SEO, isso significa que o @placeholder precisa conter HTML semanticamente relevante, e nao apenas um spinner:
@defer (on viewport) {
<comment-section [postId]="post.id" />
} @placeholder {
<section aria-label="Comments">
<h2>Comments</h2>
<p>Loading comments...</p>
</section>
}Motores de busca indexam o conteudo do placeholder durante o SSR. Um placeholder descritivo garante que a pagina permaneca semanticamente completa para crawlers e leitores de tela. Em aplicacoes que dependem de trafego organico, a presenca de marcacao estruturada no placeholder impacta diretamente o posicionamento nos resultados de busca.
Hidratacao incremental com @defer
O Angular 19 introduziu a hidratacao incremental em developer preview, e o Angular 22 a estabiliza como funcionalidade pronta para producao. A hidratacao incremental estende o @defer com um gatilho hydrate que controla quando um componente renderizado no servidor se torna interativo no cliente.
@defer (hydrate on viewport) {
<product-gallery [images]="product.images" />
}
@defer (hydrate on interaction) {
<product-reviews [productId]="product.id" />
}Diferentemente do @defer padrao, a hidratacao incremental renderiza o HTML completo do componente no servidor. O cliente recebe a marcacao completa mas posterga a hidratacao do componente ate que o gatilho seja acionado. O resultado: o navegador pinta a pagina inteira imediatamente, enquanto a execucao do JavaScript e adiada.
No caso da galeria de produtos, o HTML completo e enviado pelo servidor, mas o JavaScript do componente so e hidratado quando o elemento entra no viewport. As avaliacoes do produto, por sua vez, sao hidratadas apenas quando o usuario interage com a secao. Essa abordagem reduz drasticamente o Total Blocking Time (TBT) em paginas com multiplos componentes pesados.
A equipe do Angular reporta melhorias consistentes de 40 a 50% nos scores de LCP ao utilizar hidratacao incremental em paginas com conteudo pesado. O Angular DevTools na versao 22 permite visualizar os estados de hidratacao (pendente, hidratado, erro) diretamente no inspetor de componentes, facilitando o debugging em aplicacoes complexas.
Padroes do mundo real e estrategia de performance
Padrao 1: Dashboard pesado com multiplos paineis deferidos
Dashboards corporativos frequentemente carregam dezenas de widgets simultaneamente, impactando o tempo de carregamento inicial. O @defer permite que cada painel seja carregado independentemente, priorizando o conteudo visivel.
<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>Os graficos de vendas e o feed de atividades sao prefetchados em idle e renderizados ao entrar no viewport. O painel de exportacao permanece descarregado ate que o usuario o solicite explicitamente, economizando o download de um chunk inteiro para usuarios que nunca exportam dados. Skeleton cards no placeholder mantem a estabilidade visual do layout, evitando Cumulative Layout Shift (CLS).
Padrao 2: Carregamento condicional de funcionalidades com signals
Esse padrao e comum em aplicacoes SaaS que oferecem funcionalidades diferenciadas por plano de assinatura. O componente premium so e baixado se o usuario realmente tem acesso a ele.
export class EditorComponent {
user = inject(UserService).currentUser;
isPremium = computed(() => this.user()?.plan === 'premium');
}
// editor.component.html
@defer (when isPremium()) {
<ai-assistant />
} @placeholder {
<upgrade-banner />
}Usuarios do plano gratuito nunca baixam o chunk do assistente de IA. O banner de upgrade serve simultaneamente como placeholder e como prompt de conversao. Esse padrao demonstra como @defer pode ser utilizado nao apenas para otimizacao de performance, mas tambem para segmentacao de funcionalidades por perfil de usuario.
Armadilhas comuns a evitar
Aninhar blocos @defer com o mesmo gatilho causa downloads simultaneos de chunks, anulando o beneficio do carregamento gradual. A solucao e escalonar os gatilhos entre blocos aninhados:
// 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 />
}Outra armadilha frequente: usar @defer para componentes que ja estao no caminho critico de renderizacao. Deferir conteudo acima da dobra (above the fold) aumenta o LCP porque o navegador precisa baixar e executar o chunk antes de pintar o componente. O @defer deve ser reservado para conteudo abaixo da dobra ou acionado pelo usuario.
Um terceiro ponto de atencao envolve componentes com dependencias compartilhadas. Se dois blocos @defer utilizam o mesmo componente auxiliar, o Angular pode duplicar essa dependencia em ambos os chunks. Monitorar o tamanho dos chunks gerados com ferramentas como source-map-explorer e fundamental para identificar duplicacoes indesejadas.
@defer vs lazy loading baseado no roteador
O lazy loading pelo roteador e o @defer sao complementares, nao concorrentes. O roteador divide a aplicacao no nivel de rota, adiando modulos de funcionalidade inteiros. O @defer divide dentro de um template, adiando componentes individuais.
| Aspecto | Lazy Loading pelo Router | @defer |
|--------|-------------------|--------|
| Granularidade | Nivel de rota | Nivel de componente |
| Gatilho | Evento de navegacao | viewport, idle, interaction, hover, timer, condicao |
| Comportamento SSR | Renderizacao completa no servidor | Placeholder no servidor |
| Requer standalone | Nao (funciona com NgModules) | Sim (apenas standalone) |
| Prefetching | preloadingStrategy | Clausula prefetch on |
| Caso de uso | Modulos de funcionalidade, paginas | Widgets, paineis, UI condicional |
Uma aplicacao bem arquitetada utiliza ambas as estrategias: lazy loading pelo roteador para areas de funcionalidade de alto nivel e @defer para componentes pesados dentro dessas areas. Essa combinacao maximiza a reducao do bundle inicial enquanto mantem a experiencia de navegacao fluida.
Perguntas de entrevista sobre Angular @defer
Entrevistas tecnicas cada vez mais abordam @defer a medida que ele se torna central na estrategia de performance do Angular. A seguir estao padroes que aparecem frequentemente em perguntas de entrevista Angular.
P: O que acontece se um componente nao-standalone for colocado dentro de @defer?
O componente e carregado eagerly, independentemente do bloco @defer. O compilador do Angular nao consegue extrair componentes declarados em NgModules para chunks separados. Nenhum erro e lancado, mas a otimizacao silenciosamente falha. Em auditorias de performance, essa e uma das causas mais comuns de bundles maiores do que o esperado.
P: Como o @defer se comporta durante o SSR?
O servidor renderiza o conteudo do @placeholder. O componente deferido nunca e renderizado no lado do servidor. A hidratacao ocorre no cliente quando o gatilho e acionado (ou via hydrate on para hidratacao incremental). Por essa razao, e essencial que o placeholder contenha marcacao semanticamente significativa para SEO.
P: O @defer funciona com a estrategia de change detection OnPush?
Sim. O @defer e uma funcionalidade no nivel de template e funciona com qualquer estrategia de change detection. O componente deferido segue sua propria configuracao de deteccao de mudancas uma vez carregado. A combinacao de @defer com OnPush e uma pratica recomendada para maximizar a performance. Para aprofundar esse tema, consulte o modulo de deteccao de mudancas.
P: Qual e a diferenca entre on idle e on immediate?
on idle aguarda o navegador concluir todo o trabalho pendente via requestIdleCallback. on immediate dispara logo apos o Angular completar o passo de render inicial, sem esperar pelo estado ocioso. on immediate e util para componentes que devem carregar em breve mas nao devem bloquear a primeira pintura. Na pratica, on immediate carrega o chunk antes de on idle em paginas com muito processamento, pois nao espera a fila de tarefas esvaziar.
Para uma preparacao mais abrangente de entrevistas Angular, consulte o modulo de deteccao de mudancas e o modulo de Angular signals.
Comece a praticar!
Teste seus conhecimentos com nossos simuladores de entrevista e testes tecnicos.
Conclusao
O @defer representa uma mudanca fundamental na abordagem de otimizacao de performance no Angular, levando o lazy loading do nivel de rota para o nivel de componente com uma API puramente declarativa.
- O
@defersepara componentes standalone em chunks independentes carregados sob demanda, reduzindo o tamanho do bundle inicial sem reestruturacao de rotas - Sete tipos de gatilho (
idle,viewport,interaction,hover,timer,immediate,when) cobrem desde estrategias passivas ate acoes explicitas do usuario - A clausula
prefetch ondesacopla o download do chunk da renderizacao do componente, eliminando a latencia percebida em componentes acionados pelo usuario - A hidratacao incremental (
hydrate on) renderiza HTML completo no servidor enquanto posterga a execucao de JavaScript no cliente, gerando melhorias de 40-50% no LCP em paginas pesadas - O conteudo do
@placeholdere renderizado durante o SSR e precisa ser semanticamente relevante para SEO @defercomplementa o lazy loading pelo roteador: rotas para divisao no nivel de funcionalidade,@deferpara divisao no nivel de componente dentro dos templates- Componentes nao-standalone dentro de
@defersao carregados eagerly sem aviso, exigindo atencao durante auditorias de performance
Comece a praticar!
Teste seus conhecimentos com nossos simuladores de entrevista e testes tecnicos.
Tags
Compartilhar
Artigos relacionados

Angular 19 Zoneless: Performance e Change Detection Sem Zone.js em 2026
Guia completo sobre Angular zoneless change detection: como funciona o provideZonelessChangeDetection, migracao de Zone.js para signals, armadilhas com setTimeout e formularios reativos, SSR sem Zone.js, benchmarks de performance e o roadmap do Angular 19 ao 21.

Angular Standalone Components: Guia Completo de Migração e Boas Práticas em 2026
Guia completo sobre Angular Standalone Components com migração passo a passo via CLI, roteamento com loadComponent, eliminação de NgModules, testes e ganhos de performance. Exemplos práticos com código.

Perguntas de entrevista Angular 19: Signals, SSR e conceitos essenciais
As perguntas de entrevista Angular 19 mais comuns: Signals, hidratação incremental, detecção de mudanças sem Zone.js e novas APIs reativas com exemplos de código e respostas esperadas.