在javascript中,添加到页面上的事件处理程序数量关系到页面的整体运行性能。导致这一问题的原因是多方面的。首先,每个函数都是对象,都会占有内存,内存中的对象越多,性能就越差。其次,事先指定所有事件处理程序而导致DOM访问过多,会延迟整个页面的交互就绪时间。
事件委托
对“事件处理程序过多”问题的解决方案就是事件委托。事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。HTML代码
<ul id="ulId" > <li id="id1"> go somewhere </li> <li id="id2"> do something </li> <li id="id2"> say hello </li> </ul>
按照传统的做法,很可能像下面这样为他们添加事件处理程序:
var item1 = document.getElementById("id1"); var item2 = document.getElementById("id2"); var item3 = document.getElementById("id3"); EventUtil.addHandler(item1,"click",function(event) { location.href = "http://www.baidu.com"; }) EventUtil.addHandler(item2,"click",function(event) { //do something document.title = change document title.''; }) EventUtil.addHandler(item3,"click",function(event) { alert('hi, jack'); })
如果在一个复杂的web应用程序中,对所有的可单击的元素都采取这种方式,那么结果就会有数不清的代码用于添加事件处理程序。此时,可以利用事件委托类解决此问题。使用事件委托,只需在DOM树中尽量最高层次上添加一个事件处理程序。代码如下:var div = document.getElementById('ulId'); EventUtil.addHandler(div,'click',function(event){ event = EventUtil.getEvent(event); var target = EventUtil.getTarget(event); switch(target.id) { case "id1" : location.href = "http://www.baidu.com"; break; case "id2" : document.title = change document title.''; break; case "id3" alert('hi, jack'); break; } })
由于所有的li元素都是ul元素的子元素,而且他们的事件冒泡,所以单击事件最终都会被这个函数处理。
这种做法与传统的做法相比有如下优点:a. document对象可以很快访问到,而且可以在页面生命周期的任何时间点上为它添加事件处理程序。
b.在页面中设置处理事件程序事件更少。
c.整个页面占有的内存空间更少。
比较适合采用事件委托的事件包括click,mousedown,keydown,mouseup,keyup,keypress。
移除事件处理程序
每当给事件处理程序指定给元素时,运行中的浏览器代码与支持页面交互的javascript代码之间就会建立一个连接。这种连接越多,页面执行速度就会越慢。在不需要的时候移除事件处理程序,也是一种解决方案。内存中留有那些过时不用的“空事件处理程序”,也是造成Web应用程序内存与性能的问题的主要原因。
在两种情况下,可能会造成上述问题。第一种情况就是从文档中移除带有事件处理程序的元素时。这可能是通过纯粹的DOM操作,例如使用removeChild()和replaceChild()方法,更多的是使用innerHTML替换页面中的某一部分时候,如果带有事件处理程序的元素被替换掉,那么原来添加到元素中的事件处理程序极有可能无法被当做垃圾回收。如下示例:
<div id="id1"> <input type="button" value="click" id="button"/> </div> <script type="text/javascript"> var btn = document.getElementById("button"); btn.onclick = function() { //do something document.getElementById("id1").innerHTML("PROCESS ...") //注意此处 }; </script>
问题在于,当按钮从页面被移除时,它还带着一个事件处理程序呢。虽然按钮被移除了,但是事件处理程序和按钮还保持着引用关系。很有可能这种关系被保存在内存中。因此如果要移除一个元素,需要把元素上的所有事件处理程序同样移除走。
<script type="text/javascript"> var btn = document.getElementById("button"); btn.onclick = function() { //do something btn.onclick = null;//移除事件处理程序 document.getElementById("id1").innerHTML("PROCESS ...") //注意此处 }; </script>
另外一种情况就是卸载页面的时候。IE是在这种情况下问题最多的浏览器,尽管其他浏览器或多或少也有类似的问题。如果在页面被卸载之前没有清理干净事件处理程序,那他们就会滞留在内存中,每次加载完之后再卸载页面,内存中滞留的对象就会越来越多,因为事件处理程序占有的内存并没有释放。