I haven't been able to make a minimal reproduction I can put in a plunkr, but in my app I have an infinite loop where ngDoCheck
in the root component is called infinitely, so I'd like to be able to identify what is actually changing.
I've looked through every call in the stack trace from putting a breakpoint in ngDoCheck
but can't find anything useful.
I know that triggering change detection from within change detection can cause this kind of infinite loop (though I thought debug mode, which I have enabled, would catch it) but I can't find any instances of this manually.
Is there anything one can log or inspect that will give insight into what's causing a round of change detection?
Probably not very useful, but there's a snapshot of the stack and state of things during this loop:
May be a bit late, but still may be helpful for someone.
I found a couple of solution which can help you to find what actually cause a CD cycle.
First one, as was mention in comments is to check the source
field of Task, the easiest way is
// put this in any component which is rendered on the page
public ngDoCheck() {
console.log('doCheck', Zone.currentTask.source);
}
This will output something like this:
This is already something and you have the direction of further researching, but it's still not perfect.
To find a real place where action handler is defined we need zone's long-stack-trace
spec.
// add this, for example, in your polyfills file
import 'zone.js/dist/long-stack-trace-zone';
Now additionally to the source of task we can check data prepared by long-stack-trace
public ngDoCheck() {
console.log('doCheck', Zone.currentTask.source, Zone.currentTask.data.__creationTrace_);
}
This will output an array:
We are interested in error
property of each entry in the array.
Start investigating in console from 0 element, and then go further.
Inside this property will be a stack trace like this:
Maybe this way is overcomplicated, but this is what I've found by reading source code of Zone. Will be really glad if someone suggests an easier solution.
I created a small snippet, which can help you to extract long stack traces
function renderLongStackTrace(): string {
const frames = (Zone.currentTask.data as any).__creationTrace__;
const NEWLINE = '\n';
// edit this array if you want to ignore or unignore something
const FILTER_REGEXP: RegExp[] = [
/checkAndUpdateView/,
/callViewAction/,
/execEmbeddedViewsAction/,
/execComponentViewsAction/,
/callWithDebugContext/,
/debugCheckDirectivesFn/,
/Zone/,
/checkAndUpdateNode/,
/debugCheckAndUpdateNode/,
/onScheduleTask/,
/onInvoke/,
/updateDirectives/,
/@angular/,
/Observable\._trySubscribe/,
/Observable.subscribe/,
/SafeSubscriber/,
/Subscriber.js.Subscriber/,
/checkAndUpdateDirectiveInline/,
/drainMicroTaskQueue/,
/getStacktraceWithUncaughtError/,
/LongStackTrace/,
/Observable._zoneSubscribe/,
];
if (!frames) {
return 'no frames';
}
const filterFrames = (stack: string) => {
return stack
.split(NEWLINE)
.filter((frame) => !FILTER_REGEXP.some((reg) => reg.test(frame)))
.join(NEWLINE);
};
return frames
.filter(frame => frame.error.stack)
.map((frame) => filterFrames(frame.error.stack))
.join(NEWLINE);
}
Usage:
public ngDoCheck() {
console.log(renderLongStackTrace());
}
I found that for EventTask, zone's long-stack-trace create wrong stack traces, you can track this issue here https://github.com/angular/zone.js/issues/1195
It's worth to set Error.stackTraceLimit = Infinity;
before application bootstrap (not for production), because stack traces with angular + zone can be really looong.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With