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

Roh*_*nga 18 javascript jquery garbage-collection memory-leaks google-chrome

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

我为这个新表单再次设置了事件监听器.现在前一个表单不再是DOM的一部分,所以我应该自动对DOM元素进行垃圾回收.我也期望指向从DOM中删除的元素的侦听器函数消失.

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

我的网络应用程序的Chrome快照几分钟

如果它很重要我正在使用JSP模板语言与jquery,jquery-ui和其他一些插件.这就是我在页面上添加/删除的动态片段的样子.

<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>
Run Code Online (Sandbox Code Playgroud)

更新

如果你想查看实际代码,请参阅相关部分. 链接显示当按下清除按钮时,调用函数clearFindForm,它使用ajax请求有效地重新获取内容(HTML片段),并用获取的内容替换此jsp中的整个div.refetchContent函数的工作方式如下:以下是代码的链接,以帮助提供更好的答案.

function refetchContent(url, replaceTarget) {
  $.ajax({
    url: url,
    data: {},
    type: "GET",
    success: function (response) {
       replaceTarget.replaceWith(response);
    },
    error:   function (response) {
       showErrorMessage("Something went wrong. Please try again.");
    }
  });
}
Run Code Online (Sandbox Code Playgroud)

Ada*_*dam 5

虽然jQuery非常擅长删除通过它的方法删除的DOM元素的事件监听器(包括.html() - 只需阅读API:http://api.jquery.com/html/) - 它不会删除事件监听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();
Run Code Online (Sandbox Code Playgroud)

请注意,在上面的示例中,尽管您从DOM中删除了该元素,但不会从内存中删除该侦听器.这是因为元素仍然存在于可通过全局变量"form"访问的分离DOM树中的内存中(这是因为我没有创建使用"var"来在done函数的范围内创建初始分离的DOM树. ...有一些细微差别,jQuery无法修复坏代码,它只能做到最好.

其他2件事:

在回调或事件监听器中做所有事情(比如在点击按钮上执行此操作)会变成真正糟糕的意大利面条代码,并且很快就变得无法管理.尝试将应用程序逻辑与UI交互分开.例如,不要使用回调来单击事件来执行一堆逻辑,使用回调来单击事件来调用执行一堆逻辑的函数.

第二,也不那么重要,(我欢迎通过评论对这个观点的反馈)我认为30MB的内存是一个相当高的网络应用基线.我有一个非常密集的谷歌地图网络应用程序,在一小时左右的密集使用后达到30MB,你真的可以注意到你开始注意到它的迟缓.Lord知道如果它达到60MB会有什么作用.我认为IE <9在这一点上几乎无法使用,但就像我说的那样,我欢迎其他人对这个想法的反馈.