Anders als ngOnChanges, das nur feuert, wenn sich eine @Input-Referenz tatsächlich ändert, läuft ngDoCheck bei jedem einzelnen Change-Detection-Zyklus, der eine Komponente erreicht — unabhängig davon, ob sich etwas Relevantes geändert hat. Das macht es zu einer präzisen, abhängigkeitsfreien Sonde, um herauszufinden, welche Teilbäume unter der Standard-Change-Detection (ohne OnPush) weit häufiger geprüft werden als erwartet. Wird diese Direktive während der Entwicklung an verdächtige Elemente gehängt, deckt sie Hotspots auf, die durch instabile Bindings entstehen — etwa einen Funktionsaufruf in einem Template-Ausdruck, der bei jedem Zyklus eine neue Objektreferenz erzeugt — ohne dass der Angular-Profiler der Browser-Devtools oder Drittanbieter-Instrumentierung nötig wären. Der visuelle rote Rahmen macht aus einer abstrakten Check-Zähler-Zahl etwas, das ein Entwickler buchstäblich auf dem Bildschirm aufblitzen sieht, während er mit der App interagiert.
import { Directive, inject, ElementRef, DoCheck, Input } from '@angular/core';@Directive({selector: '[cdProfiler]',standalone: true,})export class CdProfilerDirective implements DoCheck {@Input('cdProfiler') label = 'unlabeled';private readonly el = inject(ElementRef<HTMLElement>);private checkCount = 0;private lastLogTime = 0;// DoCheck fires on EVERY change detection pass touching this host,// even when no binding actually changed -- unlike ngOnChanges.ngDoCheck(): void {this.checkCount++;const now = performance.now();if (now - this.lastLogTime > 2000) {console.warn(`[cdProfiler:${this.label}] ${this.checkCount} checks in ` +`the last ${((now - this.lastLogTime) / 1000).toFixed(1)}s`);this.el.nativeElement.style.outline =this.checkCount > 50 ? '2px solid red' : '';this.checkCount = 0;this.lastLogTime = now;}}}