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

时间:2017-12-22 06:59:01

标签: javascript

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

图表如下所示: Graph of timeline

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

因此,我怀疑某些听众已经注册,但从未注册过。

这引出了两个主要问题:

  1. 我的假设是听众是否会被添加而且永远不会 unbound似乎是明智的,或者我可以做更多确认 这种怀疑?
  2. 假设我的怀疑是正确的,我怎么能最好的去 关于跟踪事件监听器所在的代码 被添加?我已经尝试过以下方法:
    • 查看负责打开相关面板的代码,查看添加任何侦听器的位置,并注释掉这些部分以查看性能图中是否有任何更改。没有变化。
    • 重写addEventListener原型,如下所示:
  3. 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的应用程序一样,组件可以即时安装/卸载(插入DOM或从DOM中删除)。我发现这使得跟踪“杂散事件处理程序注册”这样有点棘手。所以我真正希望的是一些关于如何在诸如此类的大型/复杂项目中追踪“Stray事件处理程序”的一般调试建议。作为一名C程序员,我会打开gdb并在可能导致性能图中“侦听器”编号增加的所有内容上设置断点。我不确定在javascript世界中是否有类似的东西,即使它存在,我也不知道该怎么做。任何建议将不胜感激!

1 个答案:

答案 0 :(得分:1)

感谢大家的评论。我最终搞清楚了。

从我的OP:

  
      
  1. 我的假设是听众是否会被添加而且从未被束缚似乎是明智的,或者我可以采取更多措施来证实这种怀疑?
  2.   

事实证明,这个问题的答案是:假设是不明智的。听众根本没有机会收集垃圾。这可能比你想象的要花费更多的时间。

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

显然,像我在OP中提到的那样,选择标签并等待几分钟,根本就没有足够的时间自行进行垃圾收集;这需要更多的时间。

当我写OP时,我没有意识到用垃圾桶图标手动收集垃圾的能力......我强烈建议在进行任何疯狂的追逐之前使用它来寻找最初看起来像什么性能问题。

相关问题