事件处理程序过多导致性能下降
在 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>
例如上面这个 HTML ,如果我们要给这三个 <li> 元素添加 onclick 事件处理程序,按照常规的做法,是分别添加。但是如果页面中存在很多可单机元素,造成的结果是有大量的代码用来添加事件处理程序,性能就会下降。
此时我们可以通过事件委托技术来解决这个问题。使用事件委托,只需要在 DOM 树中尽量最高的层次上添加一个事件处理程序,如下:
EventUtil.addHandler(window, 'load', function(event) {
var list = document.getElementById('myLinks');
EventUtil.addHandler(list, 'click', function(event) {
event = EventUtil.getEvent(event);
var target = EventUtil.getTarget(event);
switch (target.id) {
case "doSomething":
document.title = "I change the title!";
break;
case "goSomewhere":
location.href = "http://www.baidu.com";
break;
case "sayHi":
alert("Hi!");
break;
default:
alert("Nothing");
break;
}
});
});
在上面的例子中,我们使用事件委托为 <ul> 元素添加了 onclick 事件处理程序。由于所有的 <li> 元素都是他的子节点,而且事件会冒泡,所以单机事件最终会被这个函数处理。
显而易见,我们通过这种方式处理事件,事前消耗会降低,也就是页面就绪时间会缩短。因为只取了一个 DOM 元素,只添加了一个事件处理程序。所有用到按钮的事件(大多数鼠标事件和键盘事件)都适合采用事件委托技术。
如果可行的话,我们甚至可以考虑为 document 对象添加一个事件处理程序,用以处理页面上发生的某种特定类型的事件。
移除事件处理程序
另外一种方案,就是在不需要的时候及时移除事件处理程序。内存中留有那些过时不用的“空事件处理程序”,也是造成 Web 应用程序内存与性能问题的主要原因。
解决方案就是:
如果你知道某个元素即将被移除,那么最好在它被移除前手动移除事件处理程序。
btn.onclick = null;