如何识别Angular2中触发一轮变化检测检测的内容(调试ngDoCheck无限循环)?

tob*_*bek 6 angular2-changedetection angular

我无法在插件中进行最小化的再现,但是在我的应用程序中,我有一个无限循环,其中ngDoCheck根组件被无限调用,所以我希望能够识别实际发生了什么变化.

我已经查看了堆栈跟踪中的每个调用,从中放入一个断点,ngDoCheck但找不到任何有用的东西.

我知道,从触发变化检测中变化检测可能会导致这种无限循环的(虽然我想调试模式下,我已经启用,会抓住它),但我不能手动找到这个任何实例.

是否有任何人可以记录或检查,以便洞察导致一轮变化检测的原因?


可能不是很有用,但是在这个循环中有一个堆栈和事物状态的快照:

ngDoCheck无限循环

Tim*_*nko 8

可能会有点晚,但是对于某人可能仍然有所帮助。

我找到了一些解决方案,可以帮助您找到真正导致CD循环的原因。

正如评论中提到的,第一个是检查sourceTask 的字段,最简单的方法是

 // put this in any component which is rendered on the page
  public ngDoCheck() {
    console.log('doCheck', Zone.currentTask.source);
  }
Run Code Online (Sandbox Code Playgroud)

这将输出如下内容:

在此处输入图片说明

这已经是东西,您有进一步研究的方向,但是还不是很完美。

为了找到定义操作处理程序的真实位置,我们需要区域的long-stack-trace规范。

// add this, for example, in your polyfills file 
import 'zone.js/dist/long-stack-trace-zone';
Run Code Online (Sandbox Code Playgroud)

现在,除了任务源之外,我们还可以检查由长堆栈跟踪准备的数据

  public ngDoCheck() {
    console.log('doCheck', Zone.currentTask.source, Zone.currentTask.data.__creationTrace_);
  }
Run Code Online (Sandbox Code Playgroud)

这将输出一个数组:

在此处输入图片说明

我们error对数组中每个条目的属性感兴趣。从0元素开始在控制台中进行调查,然后再进行下一步。

在此属性内将是一个堆栈跟踪,如下所示:

在此处输入图片说明

也许这种方式过于复杂,但这是我通过阅读Zone的源代码发现的。如果有人建议一个更简单的解决方案,将非常高兴。

更新1

我创建了一个小片段,可以帮助您提取较长的堆栈跟踪

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);
}
Run Code Online (Sandbox Code Playgroud)

用法:

  public ngDoCheck() {
    console.log(renderLongStackTrace());
  }
Run Code Online (Sandbox Code Playgroud)

更新2

我发现对于EventTask,区域的long-stack-trace创建了错误的堆栈跟踪,您可以在这里跟踪此问题:https://github.com/angular/zone.js/issues/1195

更新3

值得Error.stackTraceLimit = Infinity;在应用程序引导之前进行设置(不适用于生产),因为带有角度+区域的堆栈跟踪可能确实很有效。