Zone.js & Zoneless Angular Future
Zone.js powers Angular change detection by patching browser APIs. But it's heavy (40KB). The future is zoneless โ signals tell Angular directly what changed.
Zone.js is a library that patches (monkey-patches) browser async APIs to automatically trigger Angular change detection. It acts as a "spy" that watches all async operations and notifies Angular.
"Zone.js = spy โ har async activity pe Angular ko alert karta hai."
What Zone.js patches:
- setTimeout / setInterval / setImmediate
- Promise.then / Promise.catch / async/await
- addEventListener (all DOM events)
- XMLHttpRequest / fetch
- requestAnimationFrame
- And many more...
// Zone.js intercepts setTimeout:
setTimeout(() => {
this.count++; // Your code runs
// Zone.js then tells Angular: "run change detection!"
// Angular checks ALL components with Default strategy
}, 1000);
You never SEE Zone.js โ it's added automatically by ng new and works invisibly behind the scenes.
Zone.js works by monkey-patching โ replacing browser's native async APIs with wrapped versions.
// What browser provides:
window.setTimeout = function(callback, delay) {
// Original: just call callback after delay
};
// What Zone.js does:
window.setTimeout = function(callback, delay) {
// Zone-patched version:
const wrappedCallback = Zone.current.wrap(callback);
return originalSetTimeout.call(window, wrappedCallback, delay);
// After wrappedCallback runs โ Zone tells Angular
};
"Monkey-patching = original function ko replace karo with wrapper."
The flow:
- Browser event happens (click, timer expires, HTTP responds)
- Zone.js intercepts the event (because it patched the API)
- Your callback/handler runs
- Zone.js notifies Angular: "async operation completed"
- Angular runs change detection on the component tree
This is why Angular "just works" without manual change detection calls โ Zone.js handles all the notification behind the scenes.
Zone.js is powerful but comes with significant costs:
1. Large bundle size
// Zone.js adds ~40KB minified to your bundle
// For comparison: Angular's @core is ~120KB
// Zone.js = 25% of your core framework bundle!
2. Patches ALL APIs โ even unused ones
// Zone.js patches these even if you never use them:
// - window.onerror, document.addEventListener
// - MutationObserver, WebSocket
// - fetch, XMLHttpRequest
// Most apps use 5-10 out of 30+ patched APIs
3. Debugging complexity
// Call stacks are wrapped โ harder to debug
// Error: Cannot read property 'x' of undefined
// at ZoneAwarePromise.then (zone.js:1234)
// at XMLHttpRequest.onLoad (zone.js:2345)
// at ZoneDelegate.invoke (zone.js:3456)
// Hard to see YOUR code's actual location
4. Issues with micro-frontends
// Two Angular apps on same page:
// Zone.js creates conflicts โ multiple zones overlap
// micro-frontends need careful isolation
"Zone.js = heavy security guard โ sab pe check karta hai, slow bhi karta hai."
Angular 18+ introduced experimental zoneless change detection. This is the future of Angular applications.
// Enable zoneless (Angular 18+ experimental)
import { provideExperimentalZonelessChangeDetection } from '@angular/core';
bootstrapApplication(AppComponent, {
providers: [
provideExperimentalZonelessChangeDetection()
]
});
"Zoneless = smart home โ signals tell you what changed, no need for security guard."
How zoneless works:
- No Zone.js library at all โ 40KB saved!
- Signals are the source of truth for change detection
- When a signal changes โ Angular knows exactly which component to update
- No tree traversal โ direct notification to affected components
- Faster startup, smaller bundles, simpler debugging
What changes in zoneless:
// This is silent in zoneless (no signal, no update):
setTimeout(() => this.counter = 5, 1000);
// This works in zoneless (signal triggers update):
const counter = signal(0);
setTimeout(() => this.counter.set(5), 1000);
// Signal tells Angular directly โ no Zone.js needed!Zoneless is coming โ here's how to prepare your codebase TODAY:
1. Use signals for ALL component state
// โ
Zoneless-ready
count = signal(0);
items = signal- ([]);
user = toSignal(this.http.get
('/api/user'), { initialValue: null });
// โ Will break in zoneless
count = 0;
items: Item[] = [];
user: User | null = null;
2. Use OnPush on ALL components
@Component({
changeDetection: ChangeDetectionStrategy.OnPush // Required for zoneless
})
3. Replace subscribe() with toSignal() or async pipe
// โ Relying on Zone.js
ngOnInit() { this.service.data$.subscribe(d => this.data = d); }
// โ
Zoneless-ready
data = toSignal(this.service.data$, { initialValue: null });
// Template: {{ data() }}
4. Don't rely on Zone.js implicit behavior
// โ This won't work in zoneless:
fetch('/api/data').then(res => this.data = res.json());
// โ
Use HttpClient (always returns Observable):
this.data = toSignal(this.http.get('/api/data'), { initialValue: null });
"Abhi se signals use karo โ zoneless aane pe zero migration."
Key Takeaways
- โ Zone.js patches browser async APIs to trigger change detection automatically
- โ Zone.js adds ~40KB to bundle โ 25% of framework size
- โ Problems: large size, patches unused APIs, complex debugging, micro-frontend issues
- โ Zoneless Angular (18+) removes Zone.js โ signals replace it
- โ Prepare today: use signals, OnPush, toSignal(), async pipe
- โ Don't remove Zone.js manually โ wait for Angular's official support
Want to track your progress?
Log in to save your place and pick up where you left off.
Progress track karna chahte ho?
Login karo apni progress save karne ke liye aur jahan chhoda tha wahan se shuru karo.
Login