Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Debug Angular2 Change Detector

Tags:

angular

I'm looking to get into the gritty details of how the change detector runs in our application. Recently I discovered that we were re rendering our application far more than we needed to and filed an Angular issue. I've been able to fix all the places that I know are rendering more than they should but now I want to have an easy way to know exactly when the change detector is running, why it is running, and what components are dirty when it runs. What is the best and or easiest way for me to obtain this information?

UPDATE: So you can set a break point in AppView.detectChanges in order to break whenever the change detector runs and then stepping through that code you can see what is being checked. However, I'm still not sure how to easily determine what is triggering the change detector or who is marking the components for check.

like image 434
Tyler Davis Avatar asked Nov 28 '16 18:11

Tyler Davis


2 Answers

NOTE: this is on: "What is triggering the change detector?"

I spent some time investigating topic, but I came to conclusion it can't be done easily without modifying angular source code. However, I can share some tips how I approach this problem.

  1. I try to figure out what event (or any other async task) triggered change detection on root component ( ApplicationRef.prototype.tick ).
  2. I create a breakpoint on ApplicationRef.prototype.tick in core.js file.

enter image description here

  1. When it stops, I look for onIvokeTask method call.

enter image description here

  1. And here's the tricky part - what to do here is determined by type of action (dom event, timeout, promise resolve) and version of angular. But generally, I look for task variable in current scope. This variable stores information about action which triggered change detection. For some events (setTimeout), callback property will be exactly the same callback which I passed into the setTimeout, but for e.g. click event, it would also callback, but wrapped by some angular decorators. However, You can somehow determine action by another properties like eventName and target.

enter image description here

  1. So, the task what I found is the cause of change detector trigger.

Yeah, I know it's too complicated, but I don't know better solution. If anybody can do it better, please share it! :)

like image 139
Krzysztof Grzybek Avatar answered Oct 12 '22 23:10

Krzysztof Grzybek


Another approach is to create custom decorator to add ngDoCheck hook and log it for components in your page, the drawback of this that you'll have to add this decorator to every component in your page:

(window as any).calls = {};
export function debug() {
    return (constructor: any) => {
        if (!constructor.prototype.ngDoCheck) {
            constructor.prototype.ngDoCheck = () => {
                console.log("ngDoCheck", constructor.name);
                const calls = (window as any).calls;
                calls[constructor.name] = calls[constructor.name] ? calls[constructor.name] + 1 : 1;
            };
        }
    };
}
(window as any).resetCalls = () => (window as any).calls = {};

You can check calls in your console for some statistics of what components are getting called most. Have in mind that ngDoCheck call doesn't mean change detection runs on that component, it's indication that change detection is running on parents component.

Not yet sure how to determine consistently what's actually triggering change detection. Some ideas are overriding ngZone or ChangeDetector to log actual triggers.

like image 45
Pavel Gurecki Avatar answered Oct 13 '22 01:10

Pavel Gurecki