Advanced
Change detection, Zone.js & OnPush
How CD works, the OnPush contract, and performance tuning.
Zone.js monkey-patches async APIs (events, timers, XHR) so Angular knows when to run change detection, which by default checks every component top-down each tick.
Default CD re-reads the whole book every tick; OnPush only re-reads chapters whose bookmark (reference) moved; zoneless only re-reads the sentence that actually changed.
Key concepts
1
The OnPush strategy makes a component check only when: an @Input reference changes, an event fires within it, an async-pipe stream emits, or you call markForCheck(). On large trees this is the single biggest CD optimisation.
OnPushreference@InputmarkForCheck()
2
For hot paths, NgZone.runOutsideAngular runs work (animations, scroll handlers) without triggering CD, and ChangeDetectorRef.detach() gives manual control. Signals push toward zoneless apps where updates are surgical.
zonelessNgZone.runOutsideAngularChangeDetectorRef.detach()
3
Pitfall: mutating an object passed as an OnPush input — the reference is unchanged so the view never updates; return a new object. Interview angle: explain exactly what triggers an OnPush component to re-check.
Pitfall:Interview angle:
typescript
@Component({ changeDetection: ChangeDetectionStrategy.OnPush, /* ... */ })
export class ListComponent {
@Input() items: readonly Item[] = [];
constructor(private zone: NgZone) {}
ngAfterViewInit() {
this.zone.runOutsideAngular(() => {
window.addEventListener('scroll', this.onScroll); // no CD per scroll
});
}
}