我还没有能够进行最小化的再现,但是在我的应用程序中,我有一个无限循环,其中根组件中的ngDoCheck
被无限调用,所以我&#39 ; d希望能够识别实际上正在改变的内容。
我已经查看了堆栈跟踪中的每个调用,在ngDoCheck
中放置了一个断点,但找不到任何有用的东西。
我知道在更改检测中从触发更改检测会导致这种无限循环(虽然我认为我启用的调试模式会捕获它)但我无法理解手动查找任何此类实例。
是否有任何人可以记录或检查哪些内容可以深入了解引起一轮变更检测的内容?
可能不是很有用,但是在这个循环中有堆栈和事物状态的快照:
答案 0 :(得分:4)
可能会有点晚,但是对于某人可能仍然有所帮助。
我找到了几种解决方案,可以帮助您找到真正导致CD循环的原因。
第一个,正如评论中提到的那样,是检查Task的source
字段,最简单的方法是
// put this in any component which is rendered on the page
public ngDoCheck() {
console.log('doCheck', Zone.currentTask.source);
}
这将输出如下内容:
这已经是事情,您有进一步研究的方向,但是仍然不够完美。
要找到定义操作处理程序的真实位置,我们需要区域的long-stack-trace
规范。
// add this, for example, in your polyfills file
import 'zone.js/dist/long-stack-trace-zone';
现在除了任务源之外,我们还可以检查由长堆栈跟踪准备的数据
public ngDoCheck() {
console.log('doCheck', Zone.currentTask.source, Zone.currentTask.data.__creationTrace_);
}
这将输出一个数组:
我们对数组中每个条目的error
属性感兴趣。
从0元素开始在控制台中进行调查,然后再进一步。
在此属性内将是这样的堆栈跟踪:
也许这种方式过于复杂,但这是我通过阅读Zone的源代码发现的。 如果有人提出更简单的解决方案,我将非常高兴。
我创建了一个小片段,可以帮助您提取较长的堆栈痕迹
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);
}
用法:
public ngDoCheck() {
console.log(renderLongStackTrace());
}
我发现对于EventTask,区域的long-stack-trace会创建错误的堆栈跟踪,您可以在https://github.com/angular/zone.js/issues/1195
处跟踪此问题。值得在应用程序引导之前设置Error.stackTraceLimit = Infinity;
(不适用于生产),因为带有角度+区域的堆栈跟踪可能确实很有效。