JavaScript事件中关于性能和内存问题,长期更新

导致性能降低或内存泄漏的原因是多方面的:
    □:每个函数都是对象。都会占用内存。
    □:内存中的对象越多,性能就越差。
目前了解的提升性能的方法有:

一、事件委托。

对“事件处理程序过多”问题的解决方案就是事件委托。事件委托利用了事件冒泡,只指定一个时间处理程序,就可以管理某一类型的所有事件。
例如:click事件会一直冒泡到document层,也就是说,我们可以为这个页面指定一个onclick事件处理程序,而不必给每个单击的元素分别添加事件处理程序。以下为例:

<ul id="myLinks">
    <li id="to">三</li>
    <li id="do">个</li>
    <li id="click">li</li>
</ul>

其中包含3个被单击后会执行操作的列表项。传统做法是:

var item1 = document.getElementById("to");
var item2 = document.getElementById("do");
var item3 = document.getElementById("this");
EventUtil.addHandler(item1,"click",function(event){
    location.href = "http://www.abc.com";
});
EventUtil.addHandler(item2,"click",function(event){
    location.title = "change了一个title";
});
EventUtil.addHandler(item3,"click",function(event){
    alert("你好")
});

如果在一个复杂Web应用中,对所有可单击的元素都采用这种方式,那么结果就会有数不清的代码用于添加事件处理程序。
此时,使用&ldquo;事件委托&rdquo;可以解决这个问题。
事件委托,只需要在DOM树种尽量最高的层次上添加一个事件处理程序,如下:

// 事件委托
var list = document.getElementById("myLinks");
EventUtil.addHandler(list,"click",function(event){
    event = EventUtil.getEvent(event);
    var target = EventUtil.getTarget(event);//取得事件的目标哦
    switch(target.id){
        case "to" :
            document.title = "change了一个title";
            break;
        case "do" :
            location.href = "http://www.abc.com";
            break;
        case "this" :
            alert("你好");
            break;
    };
})

我们使用事件委托只给ul添加了一个onclick事件处理程序。由于所有的列表子元素,它们的事件会冒泡不是吗
所以单击列表项的事件最终都会被这个函数处理。事件目标是被单击的列表项,所以通过检测id属性来决定是否采取适当的操作。注意:
    □:与前面代码相比,这段代码的消耗更低,因为只取得了一个DOM,只添加了一个事件程序;
    □:这种技术占用的内存更少。
    □:如果可行的话,为document对象添加一个事件处理程序,用以处理页面上发生的各种特定类型的事件。优点:
        △:document对象很快就可以访问,而且可以在页面生命周期的任何时点上为它添加事件处理程序(无需等待DOMContentLoaded或load事件)。只要可单击的元素呈现在页面上,就可以立即具备适当的功能;
        △:在页面中设置时间处理程序所需的事件更少。只添加一个事件处理程序所需的DOM引用更少,说花的时间也更少;
        △:整个页面占用的内存空间更少,能整体提升性能。
最合适采用事件委托技术的事件:click、mousedown、mouseup、keydown、keyup、keypress。

二、移除事件处理程序。

每当将事件处理程序指定给元素时,浏览器与JavaScript代码之间就会建立一个链接。
链接越多,页面执行起来就越慢。所以,在不需要的时候移除事件处理程序,也能解决一部分性能问题。
内存中留的那些过时的&ldquo;空事件处理程序(dangling event handler)&rdquo;,也是造成Web程序内存性能问题的主因。
如果某个元素(带有事件处理程序)被innerHTML删除,那么已经添加到元素中的事件就无法被当做垃圾回收。下面:

<div id="myDiv">
    <input type="button" value="点击我吧" id="myBtn">
</div>
<script>
    var btn = document.getElementById("myBtn");
    btn.onclick = function(){
        //something
        document.getElementById("myDiv").innerHTML = "修改中。。。";
    }
</script>

一个按钮,被包裹在div中,单击此按钮就讲按钮移除并替换成一条消息。
但是问题是:即使按钮移除了,它本身还带着一个事件处理程序。
所以那么最好的方式是手工断开引用:

var btn = document.getElementById("myBtn");
btn.onclick = function(){
    //something
    btn.onclick = null;//表达了断开
    document.getElementById("myDiv").innerHTML = "修改中。。。";
}

此时,我们先移除了按钮的事件处理程序。这样确保内存可以被再次利用,而从DOM中移除按钮也做到了干净利索。
导致&ldquo;空事件处理程序&rdquo;的另一种情况,就是卸载页面的时候。
IE8及早版本问题肯定是最多,但其他浏览器问题也不少。如果在页面被卸载前没有清理干净事件处理程序,那它们就会滞留在内存中。
每次加载完页面再卸载页面时(可能是两个页面来回切换,也可能是点击了刷新按钮),内存中滞留的对象数目就会增加,因为事件处理程序占用的内存并没有被释放。
一般来说,最好的方法就是在页面卸载之前,先通过onunload事件处理程序移除所有事件处理程序。
只要是通过onload事件处理程序添加的东西,最后都要通过onunload事件处理程序将它们移除。