javascript中不需要的事件侦听器的垃圾收集

javascript中不需要的事件侦听器的垃圾收集,javascript,jquery,google-chrome,memory-leaks,garbage-collection,Javascript,Jquery,Google Chrome,Memory Leaks,Garbage Collection,我正在构建一个单页webapp。这意味着在一段时间内我会得到新的DOM元素,删除不需要的元素。例如,当我获取一个新表单时,我只需将特定div的内容替换为该表单HTML,并设置该表单元素特有的侦听器。一段时间后,我用一个新的表单实例(具有不同的ID)替换该表单的内容 我为这个新表单再次设置了事件侦听器。现在,前面的表单不再是DOM的一部分,因此DOM元素应该被自动垃圾收集。我还希望指向从DOM中删除的元素的侦听器函数消失 然而,从Chrome收集的以下个人资料表明,我的听众数量随着时间的推移而增加

我正在构建一个单页webapp。这意味着在一段时间内我会得到新的DOM元素,删除不需要的元素。例如,当我获取一个新表单时,我只需将特定div的内容替换为该表单HTML,并设置该表单元素特有的侦听器。一段时间后,我用一个新的表单实例(具有不同的ID)替换该表单的内容

我为这个新表单再次设置了事件侦听器。现在,前面的表单不再是DOM的一部分,因此DOM元素应该被自动垃圾收集。我还希望指向从DOM中删除的元素的侦听器函数消失

然而,从Chrome收集的以下个人资料表明,我的听众数量随着时间的推移而增加。你能告诉我为什么会这样吗?我试着点击“收集垃圾”按钮。但这是我得到的个人资料。我构建应用程序的方式是否有问题?有问题吗?如果有,我应该如何解决

如果有必要,我将JSP模板语言与jquery、jQueryUI和一些其他插件一起使用。 这就是我在页面上添加/删除的动态片段的样子

<script>
  $(document).ready(function() {
    $("#unique_id").find(".myFormButton").button().click(
      function() {
        $.ajax({url: "myurl.html",
          success: function(response) {
                console.log(response);
          }
        });
    });
  });
</script>

<div id="unique_id">
    <form>
      <input name="myvar" />
      <button class="myFormButton">Submit</button>
    </form>
</div>

虽然jQuery非常擅长删除通过其方法删除的DOM元素的事件监听器(包括.html()-只需阅读API:),但它不会删除DOM元素的事件监听器,因为这些元素在分离的DOM树中可能仍然有对它们的引用

例如,如果您这样做:

$.ajax({
    ....
})
    .done(function(response,status,jqXHR) {

        //create a detached DOM tree
        form = $(response)

        //add an event listener to the detached tree
        form.find('#someIDInTheResponse').on('submit',function() {

        });

        //add the form to the html
        $('#someID').html(form);
    });

//at some other point in the code
$('#someIDInTheResponse').remove();
请注意,在上面的示例中,尽管您从DOM中删除了元素,但侦听器不会从内存中删除。这是因为元素仍然存在于通过全局变量“form”可访问的分离DOM树中的内存中(这是因为我没有创建并使用“var”在done函数的范围内创建初始分离DOM树……有一些细微差别,jQuery无法修复坏代码,它只能做到最好

2其他事项:

在回调或事件侦听器中执行所有操作(如单击按钮)很快就变成了糟糕的意大利面代码,很快就变得无法管理。尝试将应用程序逻辑与UI交互分离。例如,不要使用回调来单击事件来执行一组逻辑,使用回调来单击事件来调用执行一组逻辑的函数


第二,也不太重要,(我欢迎通过评论反馈这一观点)我认为30MB的内存对于一个web应用来说是一个相当高的基线。我有一个非常密集的google maps web应用程序,在密集使用了一个小时左右后达到30MB,当你这样做的时候,你真的会注意到它开始变慢。天知道如果它达到60MB会是什么样子。我想IE我不知道你是否真的不知道替换片段时是否取消绑定/删除以前绑定的事件侦听器

我简要地查看了您在更新的问题中链接到的代码的特定部分,但除了在document ready中所做的工作之外,没有看到任何事件侦听器绑定,因此我猜您在替换文档片段时正在进行一些附加绑定。我不是jQuery专家,但在一般绑定或添加方面所有事件侦听器不会自动替换以前绑定/分配的事件侦听器

我的观点是,您应该查看是否通过“click()”(或通过其他方法)对现有元素进行绑定,而不首先解除现有事件侦听器的绑定


你可以看看to,它提供了一个点击的例子。

我不能添加评论,因为声誉问题,但要回应Adam所说的

总结一下Adam介绍的情况,这可能与jQuery无关,问题可能在普通Javascript中。但是,您没有提供足够的代码让任何人真正了解问题的根源。您对作用域封装的使用可能非常好,问题可能在其他地方

我建议您搜索查找内存泄漏原因的工具(例如,可视化/遍历整个对象/范围/引用/函数树等)

jQuery需要注意的一件事是插件和DOM的全局插入!我见过许多JS库,不仅仅是jQuery插件,都无法提供销毁程序和清理方法。最严重的问题往往是带有弹出窗口和弹出窗口的东西,例如日期选择器、对话框等,它们有一个讨厌的习惯,就是在DOM中附加层div之类的内容之后,无需将其移除

如果很多人只是尽可能地构造东西,但不处理析构函数,特别是在JS中,这需要记住,因为即使在今天这个时代,他们仍然希望您能够为正常的网页提供服务。您还应该检查插件中的析构函数,因为不是所有的函数都会连接到移除事件。事件也可以使用其他人在jQuery中以一种混乱的方式进行清理,因此流氓处理程序可能会停止执行以下清理事件

总之,jQuery是一个很好的健壮库,但请注意,仅仅因为有人依赖它并不意味着它继承了jQuery的质量


出于好奇…您检查过document.ready上的侦听器了吗?也许您需要手动GC这些侦听器。

与.empty()类似,.remove()方法从DOM中取出元素。Use.remove()方法当您要删除元素本身以及其中的所有内容时。除了元素本身之外,与元素关联的所有绑定事件和jQuery数据都将被删除。jQuery应在调用
.remove()
时自动删除所有绑定处理程序。即使您使用
.empty()
,jQuery将在内部使用
.remove()
。不完全确定
.html()
我使用的是
.html(新内容)
.replaceWi
$.ajax({
    ....
})
    .done(function(response,status,jqXHR) {

        //create a detached DOM tree
        form = $(response)

        //add an event listener to the detached tree
        form.find('#someIDInTheResponse').on('submit',function() {

        });

        //add the form to the html
        $('#someID').html(form);
    });

//at some other point in the code
$('#someIDInTheResponse').remove();