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.

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.
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.
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.
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(),
]
};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:
# Remove zone.js polyfill from angular.json build and test targets
# Then uninstall the package
npm uninstall zone.jsRedukcja 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 przezAsyncPipe) - 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
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);
}
}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.
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.
@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);
}
}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);
}
}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.
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: '' }
);
}Gotowy na rozmowy o Angular?
Ćwicz z naszymi interaktywnymi symulatorami, flashcards i testami technicznymi.
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.
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);
});
}
}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.
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 ZonelessNgZone.onUnstable-- nigdy nie emituje w trybie ZonelessNgZone.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 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. Modul 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 wywolaniachmarkForCheck() - Aplikacje SSR musza zaadoptowac
PendingTasksjako zamiennik mechanizmu detekcji stabilnosci Zone.js - Metody
NgZone.run()iNgZone.runOutsideAngular()powinny byc zachowane w bibliotekach wspoldzielonych dla zachowania kompatybilnosci wstecznej - Eksperymentalne API Angular 19 (
provideExperimentalZonelessChangeDetection) mapuje sie bezposrednio na stabilneprovideZonelessChangeDetection()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
Zacznij ćwiczyć!
Sprawdź swoją wiedzę z naszymi symulatorami rozmów i testami technicznymi.
Tagi
Udostępnij
Powiązane artykuły

Angular 18 Signals: nowe API reaktywne i detekcja zmian bez Zone.js
Kompletny przewodnik po Angular 18 Signals: input(), model(), viewChild(), tryb zoneless. Praktyczne przykłady kodu i migracja istniejących komponentów.

Angular Standalone Components: Migracja i najlepsze praktyki w 2026 roku
Kompletny przewodnik po migracji aplikacji Angular z NgModules do komponentów standalone. Obejmuje oficjalny 3-etapowy proces CLI, lazy loading, routing i najlepsze praktyki dla Angular 21.

Top 25 Pytań Rekrutacyjnych Angular: Kompletny Przewodnik do Sukcesu
25 najczęściej zadawanych pytań rekrutacyjnych z Angulara w 2026 roku. Szczegółowe odpowiedzi, przykłady kodu i wskazówki, by zdobyć stanowisko developera Angular.