内存和性能
在 JavaScript中,添加到页面上的事件处理程序数量将直接关系到页面的整体运行性能。导致这一问题的原因是多方面的。首先,每个 函数都是对象,都会占用内存;内存中的对象越多,性能就越差。其次,必须事先指定所有事件处理程 序而导致的 DOM访问次数,会延迟整个页面的交互就绪时间。
事件委托
对“事件处理程序过多”问题的解决方案就是事件委托。事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。例如,click 事件会一直冒泡到 document 层次。也就是说,我们可以为整个页面指定一个 onclick 事件处理程序,而不必给每个可单击的元素分别添加事件处理程序。
<ul id="myLinks">
<li id="goSomewhere">Go somewhere</li>
<li id="doSomething">Do something</li>
<li id="sayHi">Say hi</li>
</ul>
在这段代码里,我们使用事件委托只为<ul>元素添加了一个 onclick 事件处理程序。由于所有列 表项都是这个元素的子节点,而且它们的事件会冒泡,所以单击事件终会被这个函数处理。
移除事件处理程序
每当将事件处理程序指定给元素时,运行中的浏览器代码与支持页面交互的 JavaScript 代码之间就会建立一个连接。这种连接越多,页面执行起来就越慢。如前所述,可以采用事件委托技术,限制建立的连接数量。另外,在不需要的时候移除事件处理程序,也是解决这个问题的一种方案。内存中留有那 些过时不用的“空事件处理程序”(dangling event handler),也是造成 Web 应用程序内存与性能问题的主要原因。
使用 removeChild()和 replaceChild()方法,但更多地是发生在使用 innerHTML 替换页面中某一部分的时候。如果带有事件处理程序的元素被 innerHTML 删除了,那么原来添加到元素中的事件处理程序极有可能无法被当作垃圾回收。
如果你知道某个元素即将被移除,那么好手工移除事件处理 程序,如下面的例子所示。
<div id="myDiv">
<input type="button" value="Click Me" id="myBtn"> </div>
<script type="text/javascript">
var btn = document.getElementById("myBtn");
btn.onclick = function(){
//先执行某些操作
btn.onclick = null; //移除事件处理程序
document.getElementById("myDiv").innerHTML = "Processing..."; };
</script>
导致“空事件处理程序”的另一种情况,就是卸载页面的时候。毫不奇怪,IE8 及更早版本在这种 情况下依然是问题多的浏览器,尽管其他浏览器或多或少也有类似的问题。如果在页面被卸载之前没 有清理干净事件处理程序,那它们就会滞留在内存中。每次加载完页面再卸载页面时(可能是在两个页 面间来回切换,也可以是单击了“刷新”按钮),内存中滞留的对象数目就会增加,因为事件处理程序 占用的内存并没有被释放。
一般来说,好的做法是在页面卸载之前,先通过 onunload 事件处理程序移除所有事件处理程序。 在此,事件委托技术再次表现出它的优势——需要跟踪的事件处理程序越少,移除它们就越容易。对这 种类似撤销的操作,我们可以把它想象成:只要是通过 onload 事件处理程序添加的东西,后都要通过 onunload 事件处理程序将它们移除。