我有一个相当大的 javascript(带有 react/redux 但没有 jquery)代码库用于我正在构建的 webapp,我注意到当我在 UI 中反复打开和关闭某个面板时,监听器的数量根据Chrome 的性能时间表不断增加。
该图如下所示:
我已经允许 chrome 的性能监视器运行一两分钟,页面处于空闲状态(就在打开/关闭面板之后),希望听众可能会被垃圾收集,但事实并非如此。我在此过程中切换到其他选项卡,也希望在选项卡处于后台时监听器会被垃圾收集,但不幸的是他们没有。
因此,我怀疑一些从未注册过的听众正在注册。
这让我想到两个主要问题:
未绑定(bind)似乎是明智的,或者我可以做更多的事情来确认
这个怀疑?
关于跟踪事件监听器所在的代码
被添加?我已经尝试了以下方法:
var f = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function(type, fn, capture) {
this.f = f;
this.f(type, fn, capture);
console.trace("Added event listener on" + type);
}
即使在这样做之后,然后注释掉导致执行此 console.trace 的所有代码部分(请参阅#1),以便在打开/关闭面板时不再打印 console.trace,我注意到监听器的相同增加在性能图中。其他原因导致听众增加。我知道还有其他方法可以添加监听器,但我不清楚如何拦截所有这些可能性或使它们以这样的方式登录到 Chrome 的调试器中,以便我可以知道哪个代码负责添加它们.
编辑 :
- 在评论中的 cowbert 的建议下,我查看了此页面:
https://developers.google.com/web/tools/chrome-devtools/console/events
然后我做了以下功能:
function printListenerCount() {
var eles = document.getElementsByTagName("*");
var numListeners = 0;
for (idx in eles) { let listeners = getEventListeners(eles[idx]);
for(eIdx in listeners)
{
numListeners += listeners[eIdx].length;
}
console.log("ele", eles[idx], "listeners", getEventListeners(eles[idx]));
}
console.log("numListeners", numListeners)
}
我在多次打开/关闭面板后执行此功能,但不幸的是“numListeners”数字没有改变。
如果 numListeners 数字发生变化,我将能够在打开/关闭面板之前/之后比较结果以发现哪个元素
已经注册了额外的事件监听器,但不幸的是 numListeners 没有改变。
在 https://developers.google.com/web/tools/chrome-devtools/console/events 上还描述了一个 monitorEvents() API。 ,但函数
调用要求您指定要监视的 DOM 元素。在这种情况下,我不确定哪个 DOM 元素有额外的
听众,所以我不确定 monitorEvents() 调用将如何真正帮助我。我可以将它附加到所有 DOM 元素,类似于我的方式
编写了上面的 printListenerCount 函数,但我想我会遇到与 printListenerCount() 类似的问题-
无论出于何种原因,它都没有考虑到有问题的听众。
其他注意事项:
这是一个有点复杂的基于 reactjs(preact,技术上)的应用程序。像大多数基于 reactjs 的应用程序一样,组件会即时挂载/卸载(插入到 DOM 中或从 DOM 中删除)。我发现这使得像这样跟踪“杂散事件处理程序注册”有点棘手。所以我真正希望的是一些关于如何在诸如此类的大型/复杂项目中追踪“杂散事件处理程序”的一般调试建议。作为 C 程序员,我会打开
gdb
并在可能导致性能图中“听众”数量增加的所有内容上设置断点。我不确定在 javascript 世界中是否有类似的东西,即使有,我也不知道该怎么做。任何建议将不胜感激!
最佳答案
谢谢大家的评论。我最终弄清楚了这一点。
从我的操作:
- Does my hypothesis that listeners are getting added and never unbound seems sensible, or is there more I could be doing to confirm this suspicion?
事实证明,这个问题的答案是:假设不合理。监听器根本没有机会收集垃圾。这可能需要比您想象的更多的时间。
这是我想出来的:
我没有意识到在录制性能时间线时,可以通过单击“性能”选项卡(用于开始时间线录制的同一选项卡)中的垃圾桶图标来强制进行垃圾回收。通过在 UI 面板的重复关闭/打开后单击此图标,额外的监听器完全消失了。图表现在看起来像这样,下降是我单击垃圾桶图标的时刻:
显然,像我在 OP 中提到的那样将选项卡置于后台并等待几分钟根本没有足够的时间让垃圾收集自行发生;这需要更多的时间。
当我编写 OP 时,我不知道使用垃圾桶图标手动收集垃圾的能力......我强烈建议在进行任何野鹅追逐之前使用它来寻找最初看起来像性能问题的东西。
关于javascript - 如何追踪添加事件监听器的位置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47937156/