# Angular 19 Zoneless: Wydajnosc i Change Detection bez Zone.js
> Przewodnik techniczny po Zoneless Change Detection w Angular 19 i 20. Architektura detekcji zmian oparta na Signals, aktywacja provideZonelessChangeDetection, migracja setTimeout i Reactive Forms, SSR bez Zone.js oraz benchmarki wydajnosci.
- Published: 2026-04-27
- Updated: 2026-04-27
- Author: SharpSkill
- Tags: angular, zoneless, change-detection, performance, signals, zone-js
- Reading time: 10 min
---
Zoneless Change Detection stanowi najbardziej znaczaca zmiane architekturalna w Angular od czasu wprowadzenia standalone components. Calkowite usuniecie Zone.js z aplikacji przeklada sie na mniejsze bundle (okolo 33 KB mniej), redukcje zbednych cykli detekcji zmian o 30-40% oraz czyste stack trace bez szumu generowanego przez Zone.js. Dla programistow Angular w 2026 roku opanowanie tego mechanizmu jest kluczowe zarowno w codziennej pracy, jak i podczas przygotowania do [pytan rekrutacyjnych z Angular dotyczacych change detection](/pl/technologies/angular/interview-questions/change-detection).
> **Harmonogram wdrazania Zoneless**
>
> Angular 18 wprowadzil Zoneless jako funkcjonalnosc eksperymentalna. Angular 19 udoskonalil eksperymentalne API za pomoca `provideExperimentalZonelessChangeDetection()`. Angular 20 przeniosl je do wersji stabilnej jako `provideZonelessChangeDetection()`. Angular 21 uczynil Zoneless domyslnym ustawieniem dla nowych projektow.
## Jak dziala Change Detection oparty na Zone.js
Zanim mozna w pelni zrozumiec zalety trybu Zoneless, warto dokladnie przeanalizowac mechanizm, ktory zastepuje. Zone.js dziala poprzez monkey-patching wszystkich asynchronicznych API przegladarki: `setTimeout`, `setInterval`, `Promise.then`, `addEventListener`, `XMLHttpRequest` i kilkudziesieciu innych. Za kazdym razem, gdy jedna z tych operacji asynchronicznych zostaje zakonczona, Zone.js powiadamia Angular, ktory nastepnie uruchamia detekcje zmian w calym drzewie komponentow.
Podejscie to ma fundamentalna wade: Zone.js nie posiada zadnej informacji o tym, czy stan aplikacji faktycznie ulegl zmianie. Wywolanie `setTimeout` wykorzystywane wylacznie do celow animacyjnych nadal wyzwala pelny cykl detekcji zmian. W duzych aplikacjach z setkami komponentow ten narzut staje sie wymierny i odczuwalny.
```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
]
};
```
Mechanizm event coalescing (wprowadzony w Angular 14) czesciowo redukuje narzut poprzez laczenie wielu zdarzen w pojedynczy cykl detekcji zmian, jednak rdzen problemu pozostaje niezmieniony: detekcja zmian uruchamia sie znacznie czesciej niz jest to konieczne.
## Aktywacja Zoneless Change Detection w Angular 19 i 20
Sciezka migracji rozni sie w zaleznosci od wersji Angular. Angular 19 wykorzystuje eksperymentalne API, natomiast Angular 20 udostepnia wersje stabilna.
```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(),
]
};
```
Po zmianie providera nalezy usunac `zone.js` z tablicy polyfills w pliku `angular.json` zarowno dla targetow build, jak i test, a nastepnie odinstalowac pakiet:
```bash
# Remove zone.js polyfill from angular.json build and test targets
# Then uninstall the package
npm uninstall zone.js
```
Redukcja rozmiaru bundle jest natychmiastowa: Zone.js odpowiada za okolo 33 KB surowego kodu (10 KB po gzip), ktory jest ladowany eagerly przy starcie aplikacji.
## Co wyzwala detekcje zmian w trybie Zoneless
Bez Zone.js przechwytujacego kazda operacje asynchroniczna Angular opiera sie na jawnych powiadomieniach. Framework planuje uruchomienie detekcji zmian, gdy wystapi ktorakolwiek z ponizszych sytuacji:
- Signal odczytywany w szablonie zmieni swoja wartosc
- Zostanie wywolane `ChangeDetectorRef.markForCheck()` (automatycznie przez `AsyncPipe`)
- Zmieni sie input komponentu poprzez `ComponentRef.setInput()`
- Zostanie wykonany callback listenera szablonu lub hosta (click, input itp.)
- Wczesniej oznaczony jako dirty widok zostanie dolaczony do drzewa komponentow
```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);
}
}
```
Signals stanowia naturalne uzupelnienie trybu Zoneless. Gdy wartosc sygnalu sie zmienia, Angular wie dokladnie, ktore szablony od niego zaleza, i planuje ukierunkowana detekcje zmian wylacznie dla tych widokow.
> **OnPush jest zalecany, ale nie wymagany**
>
> Przyjecie strategii `ChangeDetectionStrategy.OnPush` to zalecany krok w kierunku zgodnosci z trybem Zoneless, ale nie jest to wymog bezwzgledny. Domyslna strategia detekcji zmian nadal dziala w trybie Zoneless. Niemniej jednak OnPush zapewnia, ze komponenty sa ponownie renderowane tylko wtedy, gdy zmienia sie ich inputy lub zostanie wywolane `markForCheck()`, co naturalnie wpisuje sie w model mentalny Zoneless.
## Migracja istniejacych aplikacji: typowe pulapki
Przejscie z Zone.js na tryb Zoneless rzadko ogranicza sie do jednolinijkowej zmiany w istniejacych aplikacjach. Kilka wzorcow, ktore opieraly sie na niejawnym zachowaniu Zone.js, wymaga jawnej obslugi.
### setTimeout i setInterval nie wyzwalaja juz aktualizacji
W trybie Zone.js callbacki `setTimeout` automatycznie wyzwalaly detekcje zmian. W trybie Zoneless tak sie nie dzieje.
```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);
}
}
```
```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);
}
}
```
### Reactive Forms wymagaja jawnego powiadomienia
Zmiany stanu formularzy za posrednictwem `FormControl.setValue()` lub `patchValue()` nie wyzwalaja automatycznie detekcji zmian w trybie Zoneless. Dwa podejscia rozwiazuja ten problem: polaczenie observabli formularza z `markForCheck()` lub eksponowanie danych formularza poprzez sygnaly.
```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: '' }
);
}
```
## Server-Side Rendering bez Zone.js
SSR w aplikacjach Angular bez Zone.js wymaga szczegolnej uwagi. Zone.js dotychczas pomagal Angular okreslac, kiedy aplikacja osiagnela stan "stabilny" odpowiedni do serializacji. Bez niego te role przejmuje serwis `PendingTasks`.
```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);
});
}
}
```
Bez `PendingTasks` Angular dokonalby serializacji strony przed zaladowaniem danych asynchronicznych, wysylajac do klienta pusta tresc zamiast prawidlowo wyrenderowanej strony.
## Benchmarki wydajnosci: Zone.js kontra Zoneless
Korzysci wydajnosciowe wynikajace z usuniecia Zone.js mozna podzielic na trzy kategorie:
| Metryka | Zone.js | Zoneless | Poprawa |
|---------|---------|----------|---------|
| Poczatkowy rozmiar bundle | +33KB surowo / +10KB gzip | 0KB narzutu | 100% redukcja |
| Cykle detekcji zmian (typowa aplikacja) | 150-300 na interakcje | 5-15 na interakcje | 80-95% mniej |
| Glebokosc stack trace | 8-12 dodatkowych ramek Zone | Czyste natywne trace | Natychmiastowa czytelnosc |
| Time to Interactive (TTI) | Baseline | 15-25% szybszy | Eliminacja bootstrapu Zone |
Najbardziej spektakularna poprawa widoczna jest w aplikacjach z intensywna aktywnoscia asynchroniczna: polling HTTP, polaczenia WebSocket, timery i zlozone handlery zdarzen. Kazda z tych operacji wczesniej wyzwalala zbedne cykle detekcji zmian, ktore tryb Zoneless calkowicie eliminuje.
> **Kompatybilnosc bibliotek**
>
> Niektore biblioteki zewnetrzne nadal wewnetrznie polegaja na Zone.js. Okna dialogowe, pewne wrappery Web Components i niektore biblioteki animacji moga zachowywac sie nieprzewidywalnie w trybie Zoneless. Przed wdrozeniem trybu Zoneless na srodowisko produkcyjne nalezy dokladnie przetestowac wszystkie integracje z bibliotekami zewnetrznymi.
## API NgZone, ktore przetrwaja migracje
Czeste nieporozumienie: usuniecie Zone.js oznacza koniecznosc usuniecia wszystkich odwolan do `NgZone`. Jest to nieprawda. Metody `NgZone.run()` i `NgZone.runOutsideAngular()` pozostaja kompatybilne z aplikacjami Zoneless i powinny byc zachowane w bibliotekach wspoldzielonych. Ich usuniecie moze spowodowac regresje wydajnosciowe w aplikacjach, ktore nadal uzywaja Zone.js i korzystaja z tych bibliotek.
Jednak trzy observable NgZone musza zostac wyeliminowane:
- `NgZone.onMicrotaskEmpty` -- nigdy nie emituje w trybie Zoneless
- `NgZone.onUnstable` -- nigdy nie emituje w trybie Zoneless
- `NgZone.onStable` -- nigdy nie emituje w trybie Zoneless
Logike zaleznac od czasu, ktora wykorzystywala te observable, nalezy zastapic uzyciem `afterNextRender()` lub `afterEveryRender()` z `@angular/core`.
## Od Angular 19 Experimental do Angular 21 Default
Ewolucja API Zoneless podaza wyrazna sciezka stabilizacji:
- **Angular 18.1**: Wprowadzenie `provideExperimentalZonelessChangeDetection()` jako API eksperymentalne
- **Angular 19**: Udoskonalenie eksperymentalnego API, szersze testy ekosystemu
- **Angular 20**: Zmiana nazwy na `provideZonelessChangeDetection()`, przeniesienie do wersji stabilnej
- **Angular 20.2**: API w pelni stabilne, bez oczekiwanych zmian behawioralnych
- **Angular 21**: Zoneless staje sie domyslnym ustawieniem dla projektow tworzonych przez `ng new`, bez koniecznosci jawnego wywolania providera
Dla zespolow pracujacych z Angular 19 sciezka aktualizacji jest prosta: aktualizacja do Angular 20, zastapienie `provideExperimentalZonelessChangeDetection` przez `provideZonelessChangeDetection` i usuniecie polyfilla `zone.js`. Angular 19 osiaga koniec wsparcia 19 maja 2026 roku, co nadaje tej migracji pilny charakter.
Przygotowanie do rozmow rekrutacyjnych z Angular? Modul [pytan rekrutacyjnych Angular dotyczacych change detection](/pl/technologies/angular/interview-questions/change-detection) na SharpSkill szczegolowo omawia wzorce detekcji zmian, w tym scenariusze Zoneless, o ktore rekruterzy pytaja coraz czesciej. Szerszy przeglad tematow oferuje przewodnik [top 25 pytan rekrutacyjnych Angular](/pl/blog/angular/top-25-angular-interview-questions). Modul [Angular Signals](/pl/technologies/angular/interview-questions/angular-signals) obejmuje z kolei model reaktywnosci, ktory umozliwia dzialanie trybu Zoneless.
## Podsumowanie
- Usuniecie Zone.js eliminuje 33 KB wagi bundle i likwiduje warstwe monkey-patchingu przechwytujaca ponad 130 API przegladarki
- Angular Signals zapewniaja jawny model reaktywnosci, ktory czyni tryb Zoneless praktycznym rozwiazaniem, automatycznie powiadamiajac szablony o zmianach stanu
- Migracja wymaga konwersji wzorcow `setTimeout`/`setInterval`, Reactive Forms oraz logiki zalezncej od czasu na podejscie oparte na sygnalach lub wywolaniach `markForCheck()`
- Aplikacje SSR musza zaadoptowac `PendingTasks` jako zamiennik mechanizmu detekcji stabilnosci Zone.js
- Metody `NgZone.run()` i `NgZone.runOutsideAngular()` powinny byc zachowane w bibliotekach wspoldzielonych dla zachowania kompatybilnosci wstecznej
- Eksperymentalne API Angular 19 (`provideExperimentalZonelessChangeDetection`) mapuje sie bezposrednio na stabilne `provideZonelessChangeDetection()` z Angular 20, co sprawia, ze aktualizacja sprowadza sie do zmiany nazwy
- Kompatybilnosc bibliotek zewnetrznych pozostaje glownym czynnikiem ryzyka i wymaga gruntownego testowania przed wdrozeniem produkcyjnym
---
Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack.
HTML version of this page: https://sharpskill.dev/pl/blog/angular/angular-19-zoneless-change-detection-performance