调试Angular2变化检测器

Tyl*_*vis 8 angular

我正在寻找有关变更检测器如何在我们的应用程序中运行的详细信息。最近,我发现我们正在重新渲染应用程序,远远超出了我们的要求,因此提出了Angular问题。我已经能够修复我所知道的所有渲染都比其应有的地方多的地方,但是现在我想有一种简单的方法来准确知道变更检测器何时运行,为何运行以及什么时候脏了哪些组件运行。对我而言,获得此信息的最佳和/或最简便的方法是什么?

更新:因此,您可以设置一个断点AppView.detectChanges,以便每当运行变更检测器时就中断,然后逐步执行该代码,您可以看到正在检查的内容。但是,我仍然不确定如何轻松确定是什么触发了变更检测器或由谁来标记要检查的组件。

Krz*_*bek 6

注意:这是在:“什么触发了变化检测器?”

我花了一些时间调查主题,但我得出的结论是,如果不修改 angular 源代码,就无法轻松完成。但是,我可以分享一些我如何解决这个问题的技巧。

  1. 我试图弄清楚是什么事件(或任何其他异步任务)触发了对根组件 ( ApplicationRef.prototype.tick) 的更改检测。
  2. ApplicationRef.prototype.tick在 core.js 文件中创建了一个断点。

在此处输入图片说明

  1. 当它停止时,我寻找onIvokeTask方法调用。

在此处输入图片说明

  1. 这是棘手的部分 - 这里要做什么取决于动作类型(dom 事件、超时、承诺解析)和 angular 版本。但一般来说,我task在当前范围内寻找变量。此变量存储有关触发更改检测的操作的信息。对于某些事件 ( setTimeout),callbackproperty 将与我传递给 的回调完全相同setTimeout,但对于例如 click 事件,它也会回调,但由一些 angular 装饰器包装。但是,您可以通过其他属性(如eventName和 )以某种方式确定操作target

在此处输入图片说明

  1. 因此,我发现的任务是更改检测器触发的原因。

是的,我知道这太复杂了,但我不知道更好的解决方案。如果有人可以做得更好,请分享它!:)


Pav*_*cki 3

另一种方法是创建自定义装饰器来添加ngDoCheck钩子并记录页面中的组件,这样做的缺点是您必须将此装饰器添加到页面中的每个组件:

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

您可以calls在控制台中检查哪些组件被调用最多的一些统计信息。请记住,ngDoCheck调用并不意味着更改检测在该组件上运行,它表明更改检测正在父组件上运行。

尚不确定如何一致地确定实际触发更改检测的内容。有些想法是压倒性的ngZoneChangeDetector记录实际的触发器。