在DOM节点上执行事件处理程序是否被节点删除? [英] Do events handlers on a DOM node get deleted with the node?

查看:91
本文介绍了在DOM节点上执行事件处理程序是否被节点删除?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

(注意:我在下面使用jQuery,但问题是一般的Javascript一个。)



说我有一个 div#formsection 其内容使用AJAX反复更新,如下所示:

  var formSection = $ ( 'DIV#formsection'); 
var newContents = $ .get(/ *下一节的URL * /);
formSection.html(newContents);

每当我更新这个div,我触发一个自定义事件,它将事件处理程序绑定到一些新添加的元素,如下所示:

  //当表单的第一部分被加载时,这将运行... 
formSection.find('select#phonenumber ').change(function(){/ * stuff * /});

...

// ...当表单的第二部分被加载时,这运行...
formSection.find('input# foo')。focus(function(){/ * stuff * /});

所以:我绑定到一些DOM节点的事件处理程序,然后删除这些DOM节点插入新的( html())和绑定事件处理程序到新的DOM节点。



我的事件处理程序是否与DOM节点一起删除?换句话说,当我加载新的部分时,很多无用的事件处理程序在浏览器内存中堆积,等待DOM节点上的事件不再存在,还是删除DOM节点时清除?



奖金问题:如何自己测试?

解决方案

事件处理函数受到与其他变量相同的垃圾回收。这意味着当解释器确定没有可能的方法来获取对该函数的引用时,它们将从内存中删除。但是简单地删除节点不能保证垃圾回收。例如,取该节点和相关联的事件处理程序

  var node = document.getElementById('test'); 
node.onclick = function(){alert('hai')};

现在可以从DOM中删除节点

  node.parentNode.removeChild(节点); 

所以节点将不再可见你的网站,但它显然仍然存在于内存中,事件处理程序也如此。

  node.onclick(); // alert hai 

只要引用节点仍然可以访问,它的关联属性(其中 onclick 是一个)将保持不变。



现在让我们尝试一下,而不是创建一个悬空变量

  document.getElementById('test')。onclick = function(){alert '海'); } 

document.getElementById('test')。parentNode.removeChild(document.getElementById('test'));

在这种情况下,似乎没有更多的方法来访问DOM节点#test,所以当运行垃圾收集循环,应该从内存中删除 onclick 处理程序。



但这是一个非常简单的案件。 Javascript使用闭包可以大大复杂地确定垃圾收集能力。让我们尝试将稍微更复杂的事件处理函数绑定到 onclick

 文档.getElementById('test')。onclick = function(){
var i = 0;
setInterval(function(){
console.log(i ++);
},1000);

this.parentNode.removeChild(this);
};

所以当您点击#test时,元素将立即被删除,但是一秒钟后,每秒钟后,您将看到一个递增的数字打印到您的控制台。节点被删除,并且不再进一步引用它,但它似乎仍然存在部分。在这种情况下,事件处理函数本身可能不会保留在内存中,但它创建的范围是。



所以我猜这个答案是这取决于。如果对删除的DOM节点有悬挂,可访问的引用,则其关联的事件处理程序仍将驻留在内存中,以及其余的属性。即使不是这种情况,事件处理函数创建的范围可能仍然在使用和内存中。在大多数情况下(并高兴地忽略IE6),最好只是信任垃圾收集器来完成工作,Javascript毕竟不是C。但是,在最后一个例子中,重要的是编写某种类型的析构函数来隐式关闭功能。


(Note: I'm using jQuery below, but the question is really a general Javascript one.)

Say I've got a div#formsection whose contents are repeatedly updated using AJAX, like this:

var formSection = $('div#formsection');
var newContents = $.get(/* URL for next section */);
formSection.html(newContents);

Whenever I update this div, I trigger a custom event, which binds event handlers to some of the newly-added elements, like this:

// When the first section of the form is loaded, this runs...
formSection.find('select#phonenumber').change(function(){/* stuff */});

...

// ... when the second section of the form is loaded, this runs...
formSection.find('input#foo').focus(function(){/* stuff */});

So: I'm binding event handlers to some DOM nodes, then later, deleting those DOM nodes and inserting new ones (html() does that) and binding event handlers to the new DOM nodes.

Are my event handlers deleted along with the DOM nodes they're bound to? In other words, as I load new sections, are lots of useless event handlers piling up in the browser memory, waiting for events on DOM nodes that no longer exist, or are they cleared out when their DOM nodes are deleted?

Bonus question: how can test this myself?

解决方案

Event handler functions are subject to the same Garbage Collection that other variables are. That means they will be removed from memory when the interpreter determines that there is no possible means to obtain a reference to the function. Simply deleting a node however does not guarantee garbage collection. For instance, take this node and associated event handler

var node = document.getElementById('test');
node.onclick = function() { alert('hai') };

Now lets remove the node from the DOM

node.parentNode.removeChild(node);

So node will no longer be visible on your website, but it clearly still exists in memory, as does the event handler

node.onclick(); //alerts hai

As long as the reference to node is still accessible somehow, it's associated properties (of which onclick is one) will remain intact.

Now let's try it without creating a dangling variable

document.getElementById('test').onclick = function() { alert('hai'); }

document.getElementById('test').parentNode.removeChild(document.getElementById('test'));

In this case, there seems to be no further way to access the DOM node #test, so when a garbage collection cycle is run, the onclick handler should be removed from memory.

But this is a very simple case. Javascript's use of closures can greatly complicate the determination of garbage collectability. Lets try binding a slightly more complex event handler function to onclick

document.getElementById('test').onclick = function() {
  var i = 0;
  setInterval(function() {
    console.log(i++);
  }, 1000);

  this.parentNode.removeChild(this);
};

So when you click on #test, the element will instantly be removed, however one second later, and every second afterwards, you will see an incremented number printed to your console. The node is removed, and no further reference to it is possible, yet it seems parts of it remain. In this case the event handler function itself is likely not retained in memory but the scope it created is.

So the answer I guess is; it depends. If there are dangling, accessible references to deleted DOM nodes, their associated event handlers will still reside in memory, along with the rest of their properties. Even if this is not the case, the scope created by the event handler functions might still be in use and in memory.

In most cases (and happily ignoring IE6) it is best to just trust the Garbage Collector to do its job, Javascript is not C after all. However, in cases like the last example, it is important to write destructor functions of some sort to implicitly shut down functionality.

这篇关于在DOM节点上执行事件处理程序是否被节点删除?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆