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;
    }
})();

