Angular @defer di 2026: Lazy Loading Deklaratif untuk Aplikasi Lebih Cepat
Blok @defer pada Angular memungkinkan lazy loading deklaratif dengan trigger viewport, interaction, dan timer. Panduan mendalam tentang prefetching, SSR, incremental hydration, dan pola optimasi performa.

Blok @defer pada Angular menyelesaikan permasalahan yang tidak pernah mampu dijangkau oleh lazy loading berbasis router: memuat komponen, directive, dan pipe secara individual sesuai kebutuhan tanpa harus merestrukturisasi aplikasi menjadi rute-rute terpisah. Diperkenalkan pada Angular 17 dan telah distabilkan hingga Angular 22, @defer mengubah proses yang sebelumnya memerlukan dynamic import, flag *ngIf, dan konfigurasi webpack menjadi satu blok template deklaratif.
@defer menginstruksikan compiler Angular untuk memecah komponen yang dibungkus ke dalam chunk JavaScript terpisah, yang hanya dimuat ketika kondisi trigger terpenuhi. Browser mengunduh lebih sedikit JavaScript pada pemuatan awal, sehingga memperbaiki skor Largest Contentful Paint (LCP) dan Time to First Byte (TTFB) tanpa memerlukan konfigurasi code-splitting secara manual.
Cara Kerja Internal @defer
Ketika compiler Angular menemukan blok @defer, seluruh standalone component, directive, dan pipe yang berada di dalamnya diekstrak ke dalam chunk terpisah. Bundle utama dikirimkan ke browser tanpa menyertakan dependensi tersebut. Pada saat runtime, Angular mengevaluasi kondisi trigger dan mengambil chunk melalui pemanggilan import() dinamis.
Blok ini mendukung empat sub-blok yang mengontrol tampilan visual selama siklus pemuatan:
@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>
}Sub-blok @placeholder ditampilkan sebelum trigger aktif. Sub-blok @loading muncul selama proses pengunduhan chunk berlangsung, dengan parameter minimum opsional yang mencegah flicker. Sub-blok @error menangkap kegagalan jaringan atau kesalahan chunk. Parameter minimum pada @loading menghindari munculnya spinner secara sekilas ketika chunk sudah tersimpan di cache dan dimuat dengan cepat.
Satu batasan yang perlu diperhatikan: setiap dependensi di dalam @defer wajib bersifat standalone. Komponen non-standalone yang dideklarasikan melalui NgModule tidak dapat di-defer dan akan dimuat secara eager terlepas dari pembungkus @defer yang digunakan.
Tipe Trigger: Menentukan Kapan Komponen Dimuat
Angular menyediakan tujuh trigger bawaan, masing-masing menargetkan strategi pemuatan yang berbeda. Beberapa trigger dapat digabungkan menggunakan tanda titik koma dan dievaluasi sebagai kondisi 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 />
}Trigger on viewport menggunakan Intersection Observer API secara internal. Trigger on idle mendelegasikan tugas ke requestIdleCallback, menjadikannya pilihan default paling aman untuk konten yang berada di bawah lipatan halaman. Trigger on timer menerima durasi dalam satuan milidetik (500ms) atau detik (3s).
Trigger when untuk Kondisi Reaktif
Selain trigger berbasis event, when menerima ekspresi boolean apa pun, termasuk pembacaan 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>
}Menggabungkan on dan when dalam satu blok adalah hal yang valid. Angular memperlakukan keduanya sebagai OR: blok dimuat ketika salah satu kondisi terpenuhi terlebih dahulu.
Prefetching: Memisahkan Pengunduhan dari Penampilan
Prefetching memisahkan waktu pengunduhan chunk dari waktu komponen ditampilkan. Mekanisme ini menghilangkan latensi yang dirasakan pengguna dengan mengambil JavaScript sebelum trigger utama aktif.
@defer (on interaction; prefetch on idle) {
<account-settings />
} @placeholder {
<button>Open settings</button>
}Pada pola ini, browser mengunduh chunk account-settings selama waktu idle. Ketika pengguna mengklik tombol, komponen langsung ditampilkan karena kode sudah tersedia di memori. Klausa prefetch on menerima tipe trigger yang sama dengan klausa on utama.
Pola yang lazim digunakan pada halaman dashboard: melakukan prefetch komponen berat saat idle sambil menunda rendering hingga elemen memasuki viewport.
@defer (on viewport; prefetch on idle) {
<chart-widget [data]="salesData()" />
} @placeholder (minimum 100ms) {
<div class="h-48 bg-muted rounded-none"></div>
}Siap menguasai wawancara Angular Anda?
Berlatih dengan simulator interaktif, flashcards, dan tes teknis kami.
@defer dan Server-Side Rendering
Pada sisi server, blok @defer hanya merender konten @placeholder secara default. Komponen yang di-defer tidak pernah diproses di server. Perilaku ini disengaja karena pengunduhan chunk hanya relevan dalam konteks browser.
Untuk konten yang kritis bagi SEO, hal ini berarti @placeholder harus berisi HTML yang bermakna secara semantik, bukan sekadar spinner:
@defer (on viewport) {
<comment-section [postId]="post.id" />
} @placeholder {
<section aria-label="Comments">
<h2>Comments</h2>
<p>Loading comments...</p>
</section>
}Mesin pencari mengindeks konten placeholder selama proses SSR. Placeholder yang deskriptif dan terstruktur dengan baik menjamin bahwa halaman tetap memiliki kelengkapan semantik yang dibutuhkan untuk peringkat pencarian yang optimal.
Incremental Hydration dengan @defer
Angular 19 memperkenalkan incremental hydration dalam tahap developer preview, dan Angular 22 telah menstabilkannya sebagai fitur yang siap produksi. Incremental hydration memperluas kemampuan @defer dengan trigger hydrate yang mengontrol kapan sebuah komponen yang sudah dirender di server menjadi interaktif di sisi klien.
@defer (hydrate on viewport) {
<product-gallery [images]="product.images" />
}
@defer (hydrate on interaction) {
<product-reviews [productId]="product.id" />
}Berbeda dengan @defer standar, incremental hydration merender HTML lengkap komponen di sisi server. Klien menerima markup yang utuh tetapi melewati proses hydration komponen hingga trigger aktif. Hasilnya: browser menampilkan seluruh halaman secara langsung, sementara eksekusi JavaScript ditunda sesuai kebutuhan.
Tim Angular melaporkan peningkatan konsisten sebesar 40-50% pada skor LCP ketika incremental hydration diterapkan pada halaman dengan konten yang padat. Angular DevTools versi 22 menyediakan visualisasi status hydration (pending, hydrated, error) langsung di component inspector.
Pola Dunia Nyata dan Strategi Performa
Pola 1: Dashboard Berat dengan Beberapa Panel yang Di-defer
<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>Setiap panel dimuat secara independen. Panel grafik penjualan dan feed aktivitas dimuat ketika terlihat di viewport, sedangkan panel ekspor tetap tidak dimuat hingga pengguna secara eksplisit mengklik tombol. Pengguna yang tidak pernah melakukan ekspor data sama sekali tidak perlu mengunduh chunk yang terkait, sehingga menghemat bandwidth secara signifikan.
Pola 2: Pemuatan Fitur Bersyarat dengan 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 />
}Pengguna pada paket gratis tidak akan mengunduh chunk AI assistant sama sekali. Banner upgrade yang menjadi placeholder berfungsi ganda sebagai indikator visual sekaligus elemen konversi yang mendorong peningkatan langganan.
Menghindari Kesalahan Umum
Menempatkan blok @defer bersarang dengan trigger yang identik menyebabkan pengunduhan chunk terjadi secara bersamaan, yang justru meniadakan manfaat lazy loading. Trigger pada blok bersarang sebaiknya dibedakan:
// 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 />
}Kesalahan lain yang sering terjadi adalah menerapkan @defer pada komponen yang berada di area atas halaman (above-the-fold). Tindakan ini justru meningkatkan LCP karena browser harus menunggu pengunduhan chunk tambahan sebelum dapat menampilkan konten utama. Blok @defer sebaiknya digunakan secara khusus untuk konten di bawah lipatan halaman atau konten yang muncul sebagai respons terhadap aksi pengguna.
@defer vs Lazy Loading Berbasis Router
Lazy loading berbasis router dan @defer saling melengkapi satu sama lain. Router lazy loading memecah kode pada level rute, menunda pemuatan seluruh feature module. @defer memecah kode di dalam template, menunda pemuatan komponen individual.
| Aspect | Router Lazy Loading | @defer |
|--------|-------------------|--------|
| Granularity | Route level | Component level |
| Trigger | Navigation event | viewport, idle, interaction, hover, timer, condition |
| SSR behavior | Full server render | Placeholder on server |
| Requires standalone | No (works with NgModules) | Yes (standalone only) |
| Prefetching | preloadingStrategy | prefetch on clause |
| Use case | Feature modules, pages | Widgets, panels, conditional UI |
Arsitektur aplikasi yang paling optimal menerapkan keduanya secara berlapis: router lazy loading untuk memisahkan halaman-halaman utama (dashboard, pengaturan, laporan), dan @defer untuk memisahkan komponen berat di dalam setiap halaman tersebut (grafik, tabel data, editor teks kaya).
Pertanyaan Interview Seputar Angular @defer
Topik @defer semakin sering diujikan dalam sesi interview teknis seiring dengan meningkatnya peran fitur ini dalam strategi performa Angular. Berikut adalah pertanyaan-pertanyaan yang kerap muncul.
T: Apa yang terjadi apabila komponen non-standalone ditempatkan di dalam blok @defer?
Komponen tersebut dimuat secara eager tanpa memperhatikan blok @defer yang membungkusnya. Compiler Angular tidak mampu mengekstrak komponen yang dideklarasikan melalui NgModule ke dalam chunk terpisah. Tidak ada error yang dilemparkan, namun optimasi secara diam-diam gagal diterapkan.
T: Bagaimana perilaku @defer pada saat SSR?
Server hanya merender konten @placeholder. Komponen yang di-defer tidak pernah dirender di sisi server. Hydration terjadi di sisi klien ketika trigger aktif (atau melalui hydrate on untuk incremental hydration).
T: Apakah @defer dapat digunakan bersamaan dengan change detection OnPush?
Ya. @defer merupakan fitur pada level template dan kompatibel dengan strategi change detection mana pun. Komponen yang di-defer mengikuti konfigurasi change detection miliknya sendiri setelah berhasil dimuat.
T: Apa perbedaan antara on idle dan on immediate?
on idle menunggu browser menyelesaikan seluruh pekerjaan yang tertunda melalui requestIdleCallback. on immediate memicu pemuatan tepat setelah Angular menyelesaikan pass render awal, tanpa menunggu kondisi idle. Trigger on immediate cocok untuk komponen yang perlu segera tersedia tetapi tidak boleh menghalangi proses first paint.
Mulai berlatih!
Uji pengetahuan Anda dengan simulator wawancara dan tes teknis kami.
Kesimpulan
@defermemecah standalone components ke dalam chunk JavaScript terpisah yang dimuat sesuai kebutuhan, mengurangi ukuran bundle awal tanpa perlu merestrukturisasi rute aplikasi- Tujuh tipe trigger (
idle,viewport,interaction,hover,timer,immediate,when) mencakup seluruh strategi pemuatan mulai dari pasif hingga yang dipicu oleh pengguna - Klausa
prefetch onmemisahkan pengunduhan chunk dari rendering komponen, menghilangkan latensi yang dirasakan pengguna saat berinteraksi dengan komponen yang di-defer - Incremental hydration (
hydrate on) merender HTML lengkap di server sambil menunda eksekusi JavaScript di klien, menghasilkan peningkatan skor LCP sebesar 40-50% pada halaman yang padat konten - Konten
@placeholderdirender selama SSR dan wajib bermakna secara semantik agar kualitas SEO tetap terjaga @defermelengkapi lazy loading berbasis router: gunakan router untuk pemecahan kode pada level rute dan@deferuntuk pemecahan kode pada level komponen di dalam template- Komponen non-standalone tidak dapat di-defer dan akan dimuat secara eager tanpa peringatan dari compiler
Mulai berlatih!
Uji pengetahuan Anda dengan simulator wawancara dan tes teknis kami.
Tag
Bagikan
Artikel terkait

Angular 19 Zoneless: Performa dan Change Detection Tanpa Zone.js
Angular zoneless change detection menghapus Zone.js untuk menghasilkan bundle lebih kecil, rendering lebih cepat, dan reaktivitas eksplisit melalui signals. Panduan mendalam migrasi dari Zone.js ke zoneless Angular, dari API eksperimental di Angular 19 hingga API stabil di Angular 20+.

Angular Standalone Components: Panduan Migrasi dan Praktik Terbaik 2026
Panduan lengkap migrasi Angular standalone components. Langkah-langkah menghapus NgModules, mengaktifkan lazy loading, dan mengadopsi standalone API di Angular 21.

Pertanyaan wawancara Angular 19: Signals, SSR, dan konsep wajib diketahui
Pertanyaan wawancara Angular 19 yang paling umum: Signals, hidrasi inkremental, zoneless change detection, dan API reaktif baru lengkap dengan contoh kode dan jawaban yang diharapkan.