# 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. - Published: 2026-04-27 - Updated: 2026-04-27 - Author: SharpSkill - Tags: angular, zoneless, change-detection, performance, signals, zone-js - Reading time: 10 min --- 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](/nl/technologies/angular/interview-questions/change-detection). Het onderwerp raakt aan architectuur, performance en Signals -- drie thema's die herhaaldelijk terugkomen in technische sollicitatiegesprekken over Angular. > **Tijdlijn van de Zoneless-adoptie** > > 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. ```typescript // app.config.ts - Traditional Zone.js setup (Angular 18-19) 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. ```typescript // app.config.ts - Angular 19 (experimental) import { ApplicationConfig } from '@angular/core'; import { provideExperimentalZonelessChangeDetection } from '@angular/core'; export const appConfig: ApplicationConfig = { providers: [ provideExperimentalZonelessChangeDetection(), // No more Zone.js patching ] }; ``` ```typescript // app.config.ts - Angular 20+ (stable) 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: ```bash # Remove zone.js polyfill from angular.json build and test targets # Then uninstall the package npm uninstall zone.js ``` Op 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. ```typescript // counter.component.ts - Signal-driven change detection import { Component, signal, computed } from '@angular/core'; @Component({ selector: 'app-counter', template: \`
{{ count() }}

Double: {{ doubled() }}

\` }) 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 `async` pipe roept intern `markForCheck()` aan wanneer een Observable een nieuwe waarde uitzendt. - **`ComponentRef.setInput()`**: het instellen van Input-properties via de ComponentRef-API activeert eveneens change detection. > **OnPush en Zoneless** > > 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. ```typescript // user-status.component.ts - Before: relies on Zone.js @Component({ selector: 'app-user-status', template: \`{{ statusMessage }}\` }) 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: ```typescript // user-status.component.ts - After: signal-based approach import { Component, signal } from '@angular/core'; @Component({ selector: 'app-user-status', template: \`{{ statusMessage() }}\` }) 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()`: ```typescript // search.component.ts - Reactive forms with zoneless 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: \`

Results for: {{ searchTerm() }}

\` }) 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. ## 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. ```typescript // data-loader.component.ts - SSR-compatible async loading 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()) {
{{ data()!.title }}
} @else {
Loading...
} \` }) 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. > **Compatibiliteit van bibliotheken van derden** > > 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: 1. Alle componenten converteren naar `ChangeDetectionStrategy.OnPush` 2. Toestandsvariabelen in templates vervangen door Signals 3. `provideZonelessChangeDetection()` activeren terwijl Zone.js in de bundel blijft 4. Functionele tests uitvoeren en eventuele problemen oplossen 5. 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`, `setInterval` of op `Promise` gebaseerde toestandswijzigingen dient te worden geconverteerd naar Signals of expliciete `markForCheck()`-aanroepen - Reactive Forms vereisen bijzondere aandacht: `valueChanges`-Observables moeten aan de view worden gekoppeld via de `async` pipe of worden geconverteerd naar Signals met `toSignal()` - 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](/nl/blog/angular/top-25-angular-interview-questions) als het dagelijkse werk met de [Angular Signals module](/nl/technologies/angular/interview-questions/angular-signals) --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/nl/blog/angular/angular-19-zoneless-change-detection-performance