Angular 19 Zoneless: Performance en Change Detection zonder Zone.js
Technische gids over Zoneless Change Detection in Angular 19 en 20. Werking van Signal-gebaseerde reactiviteit, activering van provideZonelessChangeDetection, migratieproblemen met setTimeout en Reactive Forms, SSR zonder Zone.js en prestatiebenchmarks.

Angular 19 markeert een architecturaal keerpunt in de evolutie van het framework: de experimentele introductie van Zoneless Change Detection maakt het mogelijk om Zone.js volledig uit de applicatiebundel te verwijderen en de detectie van toestandswijzigingen toe te vertrouwen aan het native Signals-systeem. Deze overgang beperkt zich niet tot een bundelverkleining van ruim 10 KB gecomprimeerd, maar elimineert fundamenteel een categorie prestatieproblemen die voortkomen uit het systematisch patchen van meer dan 130 asynchrone browser-API's door Zone.js.
Voor Angular-ontwikkelaars in 2026 is het beheersen van Zoneless Change Detection een onmisbare competentie, zowel in de dagelijkse praktijk als bij de voorbereiding op Angular interviewvragen. Het onderwerp raakt aan architectuur, performance en Signals -- drie thema's die herhaaldelijk terugkomen in technische sollicitatiegesprekken over Angular.
Angular 18 introduceerde de eerste experimentele ondersteuning voor Zoneless Change Detection als Developer Preview. Angular 19 stabiliseerde de API met provideExperimentalZonelessChangeDetection() en volledige Signals-ondersteuning. Angular 20 maakte Zoneless de aanbevolen configuratie voor nieuwe projecten met een stabiele provideZonelessChangeDetection(). Angular 21, verwacht in het najaar van 2026, genereert projecten standaard zonder Zone.js. De migratie van bestaande applicaties kan geleidelijk plaatsvinden, aangezien Zone.js en de Zoneless-modus in hetzelfde project naast elkaar kunnen bestaan.
Hoe Zone.js Change Detection werkt
Om de voordelen van de Zoneless-architectuur te begrijpen, is het noodzakelijk om eerst het mechanisme te doorgronden dat het vervangt. Zone.js is een bibliotheek die via monkey patching alle asynchrone browser-API's overschrijft: setTimeout, setInterval, Promise.then, addEventListener, XMLHttpRequest, fetch en tientallen andere interfaces. Angular maakt een eigen zone-instantie aan met de naam NgZone, die elk van deze gepatchte operaties bewaakt.
Wanneer een asynchrone operatie wordt afgerond -- bijvoorbeeld een HTTP-respons binnenkomt of een timer afloopt -- stelt Zone.js NgZone hiervan op de hoogte. NgZone initieert vervolgens een volledig change detection-cyclus die de gehele componentenboom van de root naar beneden doorloopt, waarbij de vorige waarden worden vergeleken met de huidige waarden voor elke binding in het template.
import { ApplicationConfig } from '@angular/core';
import { provideZoneChangeDetection } from '@angular/core';
export const appConfig: ApplicationConfig = {
providers: [
provideZoneChangeDetection({ eventCoalescing: true }),
// Zone.js patches ~130+ browser APIs
// Every async callback triggers change detection
]
};Het fundamentele probleem van deze aanpak ligt in de granulariteit: Zone.js weet niet welke gegevens zijn gewijzigd, maar alleen dat een of andere asynchrone operatie is afgerond. Daardoor moet Angular de gehele componentenboom controleren bij elke cyclus. In grote applicaties met honderden componenten leidt dit gedrag tot aanzienlijke en meetbare computationele overhead. Elke HTTP-request, elke timer, elke event listener produceert een volledige doorloop van het change detection-algoritme, zelfs wanneer de wijziging betrekking heeft op slechts een enkel blad-component.
Zoneless Change Detection activeren in Angular 19 en 20
De activering van Zoneless Change Detection gebeurt via een provider-functie in de applicatieconfiguratie. In Angular 19 is de API gemarkeerd als experimenteel, terwijl deze vanaf Angular 20 stabiel is.
import { ApplicationConfig } from '@angular/core';
import { provideExperimentalZonelessChangeDetection } from '@angular/core';
export const appConfig: ApplicationConfig = {
providers: [
provideExperimentalZonelessChangeDetection(),
// No more Zone.js patching
]
};import { ApplicationConfig } from '@angular/core';
import { provideZonelessChangeDetection } from '@angular/core';
export const appConfig: ApplicationConfig = {
providers: [
provideZonelessChangeDetection(),
]
};Na het configureren van de provider dient Zone.js te worden verwijderd uit de buildconfiguratie en kan het pakket worden gedeinstalleerd:
# Remove zone.js polyfill from angular.json build and test targets
# Then uninstall the package
npm uninstall zone.jsOp dit punt start de applicatie zonder Zone.js. Angular verliest het vermogen om automatisch de afronding van asynchrone operaties te detecteren en vertrouwt volledig op het Signals-systeem en expliciete notificaties om de change detection aan te sturen.
Wat de change detection activeert in Zoneless-modus
Zonder Zone.js heeft Angular alternatieve mechanismen nodig om vast te stellen wanneer de toestand van een component is gewijzigd. De primaire bron voor change detection-triggers zijn Signals, de reactieve primitieve die beschikbaar is sinds Angular 16 en in Angular 19 de voorkeursmethode voor toestandsbeheer is geworden.
Wanneer de waarde van een Signal verandert, markeert Angular uitsluitend de componenten die dat Signal in hun template uitlezen als "dirty". Alleen die componenten en hun voorouders in de boom worden gecontroleerd in de volgende cyclus. Deze granulariteit vormt het beslissende prestatievoordeel ten opzichte van de Zone.js-aanpak.
import { Component, signal, computed } from '@angular/core';
@Component({
selector: 'app-counter',
template: \`
<div class="counter">
<button (click)="decrement()">-</button>
<span>{{ count() }}</span>
<button (click)="increment()">+</button>
<p>Double: {{ doubled() }}</p>
</div>
\`
})
export class CounterComponent {
// Signal updates automatically notify the template
count = signal(0);
doubled = computed(() => this.count() * 2);
increment() {
this.count.update(v => v + 1);
// No markForCheck() needed - signal handles notification
}
decrement() {
this.count.update(v => v - 1);
}
}Naast Signals wordt de change detection in Zoneless-modus ook geactiveerd door de volgende mechanismen:
- Template event bindings: elke
(click),(input)of andere event handler in het template activeert een change detection-cyclus na de uitvoering ervan. ChangeDetectorRef.markForCheck(): markeert een component expliciet voor controle in de volgende cyclus.- Async Pipe: de
asyncpipe roept internmarkForCheck()aan wanneer een Observable een nieuwe waarde uitzendt. ComponentRef.setInput(): het instellen van Input-properties via de ComponentRef-API activeert eveneens change detection.
Componenten met changeDetection: ChangeDetectionStrategy.OnPush gedragen zich in Zoneless-modus identiek aan componenten met de Default-strategie. Zonder Zone.js vindt er geen automatische controle van de volledige boom plaats, waardoor de Default-strategie feitelijk gelijkwaardig is aan OnPush. Bestaande applicaties die al consequent OnPush gebruiken, profiteren van een bijzonder soepele migratie naar Zoneless.
Migratieproblemen: setTimeout, Reactive Forms en code van derden
De meest voorkomende foutbron bij de migratie naar Zoneless is code die impliciet afhankelijk is van Zone.js voor het propageren van toestandswijzigingen. Elke setTimeout, setInterval of op Promise gebaseerde toestandswijziging die niet via Signals of expliciete change detection-aanroepen verloopt, wordt in Zoneless-modus niet automatisch weerspiegeld in de view.
@Component({
selector: 'app-user-status',
template: \`<span>{{ statusMessage }}</span>\`
})
export class UserStatusComponent {
statusMessage = 'Loading...';
ngOnInit() {
setTimeout(() => {
// Zone.js would trigger CD here - zoneless does NOT
this.statusMessage = 'Ready';
}, 2000);
}
}De oplossing bestaat uit het converteren van de toestand naar Signals, die Angular automatisch op de hoogte stellen van de wijziging:
import { Component, signal } from '@angular/core';
@Component({
selector: 'app-user-status',
template: \`<span>{{ statusMessage() }}</span>\`
})
export class UserStatusComponent {
statusMessage = signal('Loading...');
ngOnInit() {
setTimeout(() => {
// Signal update notifies Angular automatically
this.statusMessage.set('Ready');
}, 2000);
}
}Een ander probleemgebied betreft Reactive Forms. De Observables valueChanges en statusChanges van FormControl, FormGroup en FormArray zenden waarden asynchroon uit. In Zoneless-modus moet worden gewaarborgd dat deze Observables aan de view worden gekoppeld via de async pipe of worden geconverteerd naar Signals met toSignal():
import { Component, inject, signal } from '@angular/core';
import { FormControl, ReactiveFormsModule } from '@angular/forms';
import { toSignal } from '@angular/core/rxjs-interop';
import { debounceTime, distinctUntilChanged } from 'rxjs';
@Component({
selector: 'app-search',
imports: [ReactiveFormsModule],
template: \`
<input [formControl]="searchControl" placeholder="Search..." />
<p>Results for: {{ searchTerm() }}</p>
\`
})
export class SearchComponent {
searchControl = new FormControl('');
// Convert observable to signal for automatic template updates
searchTerm = toSignal(
this.searchControl.valueChanges.pipe(
debounceTime(300),
distinctUntilChanged()
),
{ initialValue: '' }
);
}De utility toSignal() uit het pakket @angular/core/rxjs-interop vormt de ideale brug tussen de RxJS-wereld en die van Signals: het converteert elke Observable naar een Signal, waardoor emissies automatisch worden weerspiegeld in het template zonder dat Zone.js nodig is.
Klaar om je Angular gesprekken te halen?
Oefen met onze interactieve simulatoren, flashcards en technische tests.
SSR zonder Zone.js: PendingTasks en applicatiestabiliteit
Bij Server-Side Rendering vervult Zone.js een kritieke functie: het signaleert aan Angular wanneer alle asynchrone operaties zijn voltooid en de pagina "stabiel" is, dus gereed voor serialisatie en verzending naar de client. Zonder Zone.js wordt deze verantwoordelijkheid overgenomen door de PendingTasks-service.
De PendingTasks-service maakt het mogelijk om asynchrone operaties expliciet te registreren en als voltooid te markeren. Angular wacht met de serialisatie van de SSR-uitvoer totdat alle geregistreerde taken zijn afgerond.
import { Component, inject, signal } from '@angular/core';
import { PendingTasks } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { firstValueFrom } from 'rxjs';
@Component({
selector: 'app-data-loader',
template: \`
@if (data()) {
<div>{{ data()!.title }}</div>
} @else {
<div>Loading...</div>
}
\`
})
export class DataLoaderComponent {
private http = inject(HttpClient);
private pendingTasks = inject(PendingTasks);
data = signal<{ title: string } | null>(null);
ngOnInit() {
// PendingTasks.run() prevents SSR serialization until complete
this.pendingTasks.run(async () => {
const result = await firstValueFrom(
this.http.get<{ title: string }>('/api/data')
);
this.data.set(result);
});
}
}Zonder de registratie via PendingTasks zou Angular de pagina serialiseren voordat de HTTP-request is voltooid, waardoor de client een pagina ontvangt met de tekst "Loading...". De PendingTasks-service vervangt daarmee de impliciete stabiliteitsdetectie van Zone.js door een expliciet en gecontroleerd alternatief.
Voor requests die worden uitgevoerd via HttpClient geconfigureerd met provideHttpClient(), registreert Angular de pending tasks automatisch. Het handmatig inzetten van PendingTasks is uitsluitend nodig voor aangepaste asynchrone operaties, zoals WebSocket-verbindingen, native fetch-aanroepen of op timers gebaseerde initialisaties.
Prestatiebenchmarks: Zone.js vs. Zoneless
De onderstaande gegevens illustreren de meetbare verschillen tussen een Angular-applicatie met Zone.js en dezelfde applicatie na migratie naar Zoneless Change Detection.
| Metriek | Zone.js | Zoneless | Verbetering | |---------|---------|----------|-------------| | Initiele bundelgrootte | +33KB raw / +10KB gzip | 0KB overhead | 100% reductie | | Change detection cycli (typische app) | 150-300 per interactie | 5-15 per interactie | 80-95% minder | | Stack trace diepte | 8-12 extra Zone frames | Schone native traces | Directe duidelijkheid | | Time to Interactive (TTI) | Baseline | 15-25% sneller | Zone bootstrap geelimineerd |
De reductie van change detection-cycli met 80% tot 95% vloeit voort uit gerichte controle: in plaats van de gehele componentenboom te doorlopen, controleert de Zoneless-modus uitsluitend de componenten die daadwerkelijk door de wijziging worden geraakt. Bij een tabel met 1000 rijen waarvan er slechts 10 worden bijgewerkt, controleert de Zoneless-aanpak uitsluitend die 10 gewijzigde rijen in plaats van alle 1000.
Het wegvallen van de Zone.js-bootstrap vertaalt zich in een verbetering van de Time to Interactive tussen de 15% en 25%, wat bijzonder significant is op mobiele apparaten waar het parsen en uitvoeren van JavaScript proportioneel meer kost. De native stack traces, zonder de extra frames van Zone.js, vereenvoudigen bovendien het dagelijkse debuggen op substantiele wijze.
Niet alle Angular-bibliotheken zijn compatibel met de Zoneless-modus. Bibliotheken die intern afhankelijk zijn van Zone.js om change detection te activeren, functioneren niet correct zonder aanpassingen. Angular Material is volledig compatibel met Zoneless vanaf versie 19. NgRx ondersteunt Zoneless eveneens vanaf versie 19. Voor minder gangbare bibliotheken is het raadzaam om de specifieke documentatie of de issue tracker van het project te raadplegen alvorens met de migratie te beginnen.
NgZone-API's die behouden blijven
Ook na de overgang naar de Zoneless-modus blijven bepaalde NgZone-API's beschikbaar, aangezien ze een belangrijke rol spelen bij geleidelijke migratie. De NgZone-service kan nog steeds worden geinjecteerd, maar gedraagt zich in Zoneless-modus als een no-op-implementatie.
NgZone.runOutsideAngular() is een veelgebruikte optimalisatietechniek die code uitvoert buiten de Angular-zone om onnodige change detection-cycli te voorkomen. In Zoneless-modus heeft deze aanroep geen effect, maar kan deze in de code blijven staan zonder fouten te veroorzaken. Dit vergemakkelijkt de migratie, omdat bestaande code niet onmiddellijk hoeft te worden opgeschoond.
NgZone.run() dwingt uitvoering af binnen de Angular-zone. In Zoneless-modus voert het de callback eenvoudigweg synchroon uit. Ook deze API blijft achterwaarts compatibel.
Voor nieuwe code die in Zoneless-modus wordt geschreven, zijn deze API's niet langer relevant. Het verdient de voorkeur om te vertrouwen op Signals, ChangeDetectorRef.markForCheck() en de PendingTasks-service voor het expliciet aansturen van change detection.
Van Angular 19 experimenteel naar Angular 21 standaard
De introductie van Zoneless Change Detection volgt het beproefde patroon van Angular voor ingrijpende architectuurwijzigingen: experimenteel, stabiel, standaard.
In Angular 19 werd provideExperimentalZonelessChangeDetection() geintroduceerd als Developer Preview. De API kon nog wijzigen in minor-releases en het Angular-team adviseerde het gebruik uitsluitend in nieuwe projecten of voor verkennende tests.
Met Angular 20 werd de API als stabiel verklaard onder de naam provideZonelessChangeDetection(). Het ng new-commando biedt Zoneless aan als configuratieoptie en de officiele documentatie beveelt deze modus aan voor alle nieuwe projecten. Bestaande applicaties kunnen geleidelijk migreren.
In Angular 21, verwacht in het najaar van 2026, genereert ng new projecten standaard zonder Zone.js. Zone.js blijft beschikbaar als optionele afhankelijkheid voor projecten die het expliciet nodig hebben, maar wordt niet langer automatisch geinstalleerd.
Voor de migratie van bestaande projecten beveelt het Angular-team een gefaseerde aanpak aan:
- Alle componenten converteren naar
ChangeDetectionStrategy.OnPush - Toestandsvariabelen in templates vervangen door Signals
provideZonelessChangeDetection()activeren terwijl Zone.js in de bundel blijft- Functionele tests uitvoeren en eventuele problemen oplossen
- Zone.js verwijderen uit de polyfills
Dit stappenplan minimaliseert het risico en maakt het mogelijk om problemen vroegtijdig te identificeren, aangezien Angular met de geactiveerde Zoneless-provider en Zone.js nog in de bundel waarschuwingen afgeeft wanneer change detection via Zone.js wordt geactiveerd.
Conclusie
Zoneless Change Detection markeert een fundamentele architectuurwijziging voor Angular. De belangrijkste punten laten zich als volgt samenvatten:
- Zone.js onderschept alle asynchrone browser-API's en activeert een volledige change detection-cyclus bij de afronding van elke operatie, wat bij grote applicaties leidt tot aanzienlijke prestatieproblemen
provideZonelessChangeDetection()schakelt de Zoneless-modus in en elimineert de afhankelijkheid van Zone.js volledig- Signals vormen het fundament van de Zoneless-architectuur en maken gerichte, componentspecifieke change detection mogelijk in plaats van een controle van de gehele componentenboom
- Bestaande code die gebruikmaakt van
setTimeout,setIntervalof opPromisegebaseerde toestandswijzigingen dient te worden geconverteerd naar Signals of explicietemarkForCheck()-aanroepen - Reactive Forms vereisen bijzondere aandacht:
valueChanges-Observables moeten aan de view worden gekoppeld via deasyncpipe of worden geconverteerd naar Signals mettoSignal() - SSR-applicaties maken gebruik van de
PendingTasks-service als vervanging voor de impliciete stabiliteitsdetectie van Zone.js - De prestatieverbeteringen varieren van 15-25% bij het opstarten tot 80-95% reductie in change detection-cycli
- De migratie kan incrementeel plaatsvinden, aangezien Zone.js en de Zoneless-modus in hetzelfde project naast elkaar kunnen bestaan
- Vanaf Angular 21 wordt Zoneless de standaard voor nieuwe projecten, waardoor beheersing van deze architectuur onmisbaar is voor zowel de top 25 Angular interviewvragen als het dagelijkse werk met de Angular Signals module
Begin met oefenen!
Test je kennis met onze gespreksimulatoren en technische tests.
Tags
Delen
Gerelateerde artikelen

Angular 18: Signals en nieuwe features
Angular 18 Signals, zoneless change detection en de nieuwe signal-gebaseerde API's voor performantere applicaties.

Angular Standalone Components: migratie en best practices in 2026
Volledige gids voor het migreren van Angular-applicaties van NgModules naar standalone components. Behandelt de officiƫle CLI-migratie in 3 stappen, lazy loading, routing en best practices voor Angular 21.

Top 25 Angular Sollicitatievragen: Complete Gids voor Succes
De 25 meest gestelde Angular sollicitatievragen in 2026. Uitgebreide antwoorden, codevoorbeelden en tips om de Angular developer-rol binnen te halen.