简体   繁体   English

如何追踪事件监听器的添加位置?

[英]How do I track down where event listener is getting added?

I have a fairly good sized javascript (with react/redux but no jquery) codebase for a webapp I'm building, and I've noticed that when I repeatedly open and close a certain panel within the UI, the number of listeners according to Chrome's performance timeline keeps increasing. 我有一个相当好的javascript(有react / redux但没有jquery)代码库用于我正在构建的webapp,我注意到当我在UI中反复打开和关闭某个面板时,监听器的数量根据Chrome的性能时间表不断增加。

The graph looks like this: 该图如下所示: 时间线图

I have allowed the chrome's performance monitor run for a good minute or two with the page sitting idle (just after opening/closing the panel a bunch), hoping that perhaps the listeners will get garbage collected, but they are not. 我已经允许chrome的性能监视器运行一两分钟,页面处于空闲状态(在打开/关闭面板之后),希望听众可能会收集垃圾,但事实并非如此。 I've switched to other tabs during this process, also hoping that the listeners will get garbage collected when the tab is backgrounded, but they unfortunately are not. 我在这个过程中切换到其他选项卡,也希望听众在选项卡背景时收集垃圾,但不幸的是,他们不会。

I therefore suspect that some listeners are getting registered that are never unregistered. 因此,我怀疑有些听众正在注册,但从未注册过。

This leads me to two main questions: 这引出了两个主要问题:

  1. 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? 我的假设是听众是否会得到补充并且从未被束缚似乎是明智的,或者我可以采取更多措施来证实这种怀疑?
  2. Assuming my suspicion is correct, how can I best go about tracking down the code where the event listener(s) is/are being added? 假设我的怀疑是正确的,我怎样才能最好地追踪添加事件监听器的代码? I have already tried the following: 我已经尝试过以下方法:
    • Looked at the code that is responsible for opening the panel in question, seeing where it adds any listeners, and commenting out those portions to see if there's any change in the performance graph. 查看负责打开相关面板的代码,查看它添加任何侦听器的位置,并注释掉这些部分以查看性能图中是否有任何更改。 There is not a change. 没有变化。
    • Overridden the addEventListener prototype like so: 像这样重写addEventListener原型:

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

Even after doing this, then commenting out all code portions that cause this console.trace to be executed (see #1) such that the console.trace is no longer printed upon open/close of the panel, I notice the same increase in listeners in the performance graph. 即使在这样做之后,然后注释掉导致执行此console.trace的所有代码部分(参见#1),以便在打开/关闭面板时不再打印console.trace,我注意到听众的增加相同在性能图表中。 Something else is causing the listeners to increase. 其他一些因素导致听众增加。 I understand that there are other ways that listeners can be added, but it's not clear to me how to intercept all of those possibilities or cause them to be logged in Chrome's debugger in such a way that I can tell which code is responsible for adding them. 我知道还有其他方法可以添加监听器,但是我不清楚如何拦截所有这些可能性或导致它们以这样的方式登录Chrome的调试器,以便我可以告诉哪些代码负责添加它们。

Edit : - At the suggestion of cowbert in the comments, I took a look at this page: https://developers.google.com/web/tools/chrome-devtools/console/events 编辑 : - 根据评论中cowbert的建议,我看了一下这个页面: https//developers.google.com/web/tools/chrome-devtools/console/events

I then made the following function: 然后我做了以下功能:

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

I execute this function after having opened/closed the panel a bunch of times, but unfortunately the "numListeners" figure doesn't change. 我打开/关闭面板多次后执行此功能,但不幸的是“numListeners”数字没有改变。 If the numListeners figure changed, I would be able to diff the results before/after having open/closed the panel to discover which element has the extra event listener registered to it, but unfortunately numListeners does not change. 如果numListeners数字发生了变化,我可以在打开/关闭面板之前/之后对结果进行区分,以发现哪个元素有额外的事件监听器注册到它,但不幸的是numListeners没有改变。

There is also a monitorEvents() API described on https://developers.google.com/web/tools/chrome-devtools/console/events , but the function call requires that you specify a DOM element that you wish to monitor. https://developers.google.com/web/tools/chrome-devtools/console/events上还介绍了monitorEvents()API,但函数调用要求您指定要监视的DOM元素。 In this situation, I'm not sure which DOM element has the extra listeners, so I'm not sure how the monitorEvents() call will really help me. 在这种情况下,我不确定哪个DOM元素有额外的侦听器,所以我不确定monitorEvents()调用将如何真正帮助我。 I could attach it to all DOM elements, similar to how I've written the printListenerCount function above, but I presume I'd run into a similar problem that I ran into with printListenerCount() -- for whatever reason, it's not accounting for the listener(s) in question. 我可以将它附加到所有DOM元素,类似于我上面编写的printListenerCount函数,但我认为我遇到了类似的问题,我遇到了printListenerCount() - 无论出于何种原因,它都不能解决有问题的听众。

Other notes: This is a somewhat complicated reactjs (preact, technically) based application. 其他说明:这是一个有点复杂的反应(基于预制,技术)的应用程序。 Like most reactjs based apps, components get mounted/unmounted (inserted into and removed from the DOM) on the fly. 与大多数基于reactjs的应用程序一样,组件可以即时安装/卸载(插入DOM或从DOM中删除)。 I'm finding that this makes tracking down "stray event handler registrations" like this a bit tricky. 我发现这使得跟踪“杂散事件处理程序注册”这样有点棘手。 So what I'm really hoping for is some general debugging advice about how to track down "Stray event handlers" in large/complex projects such as this. 所以我真正希望的是一些关于如何在诸如此类的大型/复杂项目中追踪“Stray事件处理程序”的一般调试建议。 As a C programmer, I would open gdb and set a breakpoint on everything that can possibly cause the "listeners" number in the performance graph to increase. 作为C程序员,我会打开gdb并在所有可能导致性能图中“侦听器”编号增加的内容上设置断点。 I'm not sure if there's an analog of that in the javascript world, and even if it there, I'm just not sure how to do it. 我不确定在javascript世界中是否有类似的东西,即使它存在,我也不知道该怎么做。 Any advice would be much appreciated! 任何建议将不胜感激!

Thanks for your comments, everyone. 谢谢大家的评论。 I ended up figuring this out. 我最终搞清楚了。

From my OP: 从我的OP:

  1. 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? 我的假设是听众是否会得到补充并且从未被束缚似乎是明智的,或者我可以采取更多措施来证实这种怀疑?

It turns out that the answer to this question is: The hypothesis is not sensible. 事实证明,这个问题的答案是:假设是不明智的。 The listeners simply haven't had a chance to get garbage collected yet. 听众根本没有机会收集垃圾。 It can take some more time than you might think. 这可能比你想象的要花费更多的时间。

Here's how I figured it out: I failed to realize that while recording a performance timeline, it's possible to force a garbage collection by clicking on the trash can icon in the Performance tab (same tab used to start the timeline recording). 以下是我弄清楚的方法:我没有意识到,在录制性能时间线时,可以通过单击“性能”选项卡中的垃圾桶图标(用于启动时间线录制的相同选项卡)强制进行垃圾收集。 By clicking this icon after repeated closings/openings of the UI panel, the extra listeners completely went away. 通过在UI面板重复关闭/打开后单击此图标,额外的听众完全消失了。 The graph now looks like this, with the dips being moments where I clicked the trash icon: 图表现在看起来像这样,逢低是我点击垃圾桶图标的时刻: 使用手动GC的性能时间表

Apparently, backgrounding the tab and waiting a couple of minutes like I mentioned in the OP is simply not enough time for garbage collection to occur on its own; 显然,像我在OP中提到的那样,选择标签并等待几分钟根本就没有足够的时间来自行进行垃圾收集; It takes some more time than that. 这需要更多的时间。

I wasn't aware of the ability to manually collect garbage with the trash can icon when I wrote the OP... I strongly recommend using it before going on any wild goose chases hunting down what might at first look like a performance problem. 当我写OP时,我没有意识到用垃圾桶图标手动收集垃圾的能力......我强烈建议在进行任何疯狂的追逐之前使用它,以寻找可能最初看起来像性能问题的东西。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM