This project shows you how the component tree in Angular is updated. The time shown on the component nodes in the tree is the interval between ngDoCheck and ngAfterViewChecked.
$ git clone https://github.com/Angular-RU/change-detection-tree cd-tree && cd cd-tree
$ npm install # install all dependencies
$ ng serve # worked with jit or aot
✅ ChangeDetection.Default + NgZone (static tree + projection):
Example: https://stackblitz.com/github/Angular-RU/change-detection-tree
✅ ChangeDetection.OnPush + NgZone (random generate tree):
Example: https://stackblitz.com/github/Angular-RU/change-detection-tree/tree/onpush
✅ ChangeDetection.OnPush + Async pipe - without ngZone (random generate tree):
Example: https://stackblitz.com/github/Angular-RU/change-detection-tree/tree/onpush-async-without-zone
✅ ChangeDetection.Default + Async pipe + ngZone (random generate tree):
Example: https://stackblitz.com/github/Angular-RU/change-detection-tree/tree/async-pipe
❌ ChangeDetection.Default + Async pipe + Reactive Forms - without ngZone:
Example: In progress
❌ Custom state-management (services):
Example: In progress
❌ NgRx:
Example: In progress
❌ MobX:
Example: In progress
❌ Web-worker platform:
Example: In progress
- Detect problem with Zone
Copy the code and paste it into the console. If your component tree too often calls Application.tick() your application will disappear.
let [root] = getAllAngularRootElements();
let appRoot = ng.probe(root);
let [rootComponent] = appRoot.injector.get(ng.coreTokens.ApplicationRef).components;
let ChangeDetectorRef = rootComponent.changeDetectorRef.constructor.prototype;
ChangeDetectorRef.constructor.prototype.detectChanges = (function () {
let oldDC = ChangeDetectorRef.constructor.prototype.detectChanges;
let map = new WeakMap();
return function () {
Zone.root.run(() => showChangeDetection(this));
return oldDC.apply(this, arguments);
}
function showChangeDetection (changeDetector) {
let view = changeDetector._view;
modifyNodeOpacity(view, fade);
modifyNodeOpacity(view, (node) => {
let timeout = map.get(node.renderElement);
if (timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(() => show(node), 1000);
map.set(node.renderElement, timeout);
});
}
function modifyNodeOpacity (view, modifier) {
view.nodes.forEach(node => {
if (node && node.renderElement && node.renderElement.style) {
modifier(node);
}
});
}
function fade (node) {
let { style } = node.renderElement;
let opacity = parseFloat(style.opacity) || 1;
let newOpacity = opacity - 0.01;
style.display = 'block';
style.opacity = newOpacity > 0 ? newOpacity : 0;
}
function show (node) {
let { style } = node.renderElement;
style.display = 'block';
style.opacity = 1;
}
})();