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

标签 javascript

我有一个相当大的 javascript(带有 react/redux 但没有 jquery)代码库用于我正在构建的 webapp,我注意到当我在 UI 中反复打开和关闭某个面板时,监听器的数量根据Chrome 的性能时间表不断增加。

该图如下所示:
Graph of timeline

我已经允许 chrome 的性能监视器运行一两分钟,页面处于空闲状态(就在打开/关闭面板之后),希望听众可能会被垃圾收集,但事实并非如此。我在此过程中切换到其他选项卡,也希望在选项卡处于后台时监听器会被垃圾收集,但不幸的是他们没有。

因此,我怀疑一些从未注册过的听众正在注册。

这让我想到两个主要问题:

  • 我是否假设听众越来越多,但从不
    未绑定(bind)似乎是明智的,或者我可以做更多的事情来确认
    这个怀疑?
  • 假设我的怀疑是正确的,我怎样才能最好地去
    关于跟踪事件监听器所在的代码
    被添加?我已经尝试了以下方法:
  • 查看负责打开相关面板的代码,查看它在何处添加任何监听器,并注释掉这些部分以查看性能图中是否有任何更改。没有变化。
  • 像这样覆盖 addEventListener 原型(prototype):

  • 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 世界中是否有类似的东西,即使有,我也不知道该怎么做。任何建议将不胜感激!

    最佳答案

    谢谢大家的评论。我最终弄清楚了这一点。

    从我的操作:

    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?


    事实证明,这个问题的答案是:假设不合理。监听器根本没有机会收集垃圾。这可能需要比您想象的更多的时间。

    这是我想出来的:
    我没有意识到在录制性能时间线时,可以通过单击“性能”选项卡(用于开始时间线录制的同一选项卡)中的垃圾桶图标来强制进行垃圾回收。通过在 UI 面板的重复关闭/打开后单击此图标,额外的监听器完全消失了。图表现在看起来像这样,下降是我单击垃圾桶图标的时刻:
    Performance timeline with manual GC

    显然,像我在 OP 中提到的那样将选项卡置于后台并等待几分钟根本没有足够的时间让垃圾收集自行发生;这需要更多的时间。

    当我编写 OP 时,我不知道使用垃圾桶图标手动收集垃圾的能力......我强烈建议在进行任何野鹅追逐之前使用它来寻找最初看起来像性能问题的东西。

    关于javascript - 如何追踪添加事件监听器的位置?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47937156/

    相关文章:

    javascript - 如何将 'this' 从 A 类传递到 B 类?

    javascript - for 循环在除对象之外的其他对象上

    javascript - 在哪里可以找到 R-to-JavaScript 编译器?

    javascript - 为什么本地状态的更改不会进入全局状态?

    javascript - Angular 遍历选择选项并设置选定值

    javascript - 在同一页面上有多个 jquery 选项卡

    javascript - 将 YES/NO 转换为 true/false 的更优雅的方法

    javascript - 在按钮单击 React 上渲染一个额外的弹出对话框

    javascript - YouTube 360​​ 视频 iframe 在移动浏览器中不起作用

    javascript - Meteor:将 RegExp 对象保存到 session