首页 » JavaScript » 移除事件处理程序

移除事件处理程序

每当将事件处理程序指定给元素时,运行中的浏览器代码与支持页面交互的的代码之间就会建立一个连接。这种链接越多,页面执行起来就越慢。如前所述,可以采用事件委托技术,限制建立的链接数量。另外,在不需要的时候移除事件处理程序,也是解决这个问题的一种方案。内存中留有那些过时不用的“空时间处理程序”,也是造成Web引用程序内存与性能问题的主要原因。

在两种情况下,可能会造成上述问题。第一种情况就是从文档中移除带有事件处理程序元素时。这可能是通过纯粹的DOM操作,例如使用removeChild()和replaceChild()方法,但更多地是发生在使用innerHTML替换页面中某一部分的时候。如果带有事件处理程序的元素被innerHTML删除了,那么原来添加到元素汇总的事件处理程序极有可能无法被当作垃圾回收。来看下面的例子:

<div id="myDiv">
    <input type="button" value="Click Me" id="myBtn">
</div>
var btn = document.getElementById("myBtn");
btn.onclick = function () {
    //先执行某些操作
    document.getElementById("myDiv").innerHTML = "Processing…";
};

这里,有一个按钮被包含在<div>元素中。为避免双击,单击这个按钮时就将按钮移除并替换成一条消息;这是网站设计中非常流行的一种做法。但问题在于,当按钮被从页面中移除时,它还带有一个事件处理程序。在<div>元素设置innerHTML可以把按钮移走,但事件处理程序仍然与按钮保持着引用关系。有的浏览器(尤其是IE)在这种情况下不会做出恰当地处理,它们很有可能会将对元素和对事件处理吃呢供需的引用都保存在内存中。如果你知道某个元素即将被移除,那么最好手工移除事件处理程序,如下面的例子所示:

var btn = document.getElementById("myBtn");
btn.onclick = function () {
    //先执行某些操作
    btn.onclick = null;
    document.getElementById("myDiv").innerHTML = "Processing…"
};

再次,我们在设置<div>的innerHTML属性之前,先移除了按钮的事件处理程序。这样就确保了内存可以被再次利用,而从DOM中移除按钮也做到了干净利索。

采用事件委托也有助于解决这个问题。如果事先知道将来有可能使用innerHTML替换掉页面中的一部分,那么就可以不直接把事件处理程序添加到该部分的元素中。而通过把事件处理程序指定给较高层次的元素,同样能够处理该区域中的事件。

导致“空事件处理程序”的另一种情况,就是卸载页面的时候。好不奇怪,IE在这种情况下依然是最多的浏览器,尽管其它浏览器或多或少也有类似的问题。如果页面被卸载之前没有清理干净事件处理程序,那它们就会滞留在内存中。每次加载完页面在卸载之前卸载页面时(可能是在两个页面间来回切换,也可以单击了“刷新按钮”),内存中滞留的对象就会增加,因为事件处理程序占用内存并没有被释放。

一般来说,最好的做法是在页面卸载之前,先通过onunload事件处理程序移除所有事件处理程序。在此,事件委托技术再次表现出它的优势——需要跟踪的事件处理程序越少,移除它们就越容易。对这种类似撤销的操作,我们可以把它想象成:只要是通过onload事件处理程序添加的东西,最有都要通过onunload事件处理程序将它们移除。

不要忘了,使用onunload事件处理程序意味着页面不会被缓存在bfcache中。如果你在意这个问题,那么只能在IE中通过onunload来移除事件处理程序了。

此文章发表在 JavaScript. 将 固定链接 加入收藏.