Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can you identify what's triggering round of change detection detection in Angular2 (debugging ngDoCheck infinite loop)?

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:

ngDoCheck infinite loop

like image 807
tobek Avatar asked Mar 31 '17 20:03

tobek


1 Answers

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:

enter image description here

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:

enter image description here

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:

enter image description here

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.

Update 1

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

Update 2

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

Update 3

It's worth to set Error.stackTraceLimit = Infinity; before application bootstrap (not for production), because stack traces with angular + zone can be really looong.

like image 133
Timofey Yatsenko Avatar answered Nov 15 '22 22:11

Timofey Yatsenko