JS 13.5-13.6 内存和性能&模拟事件

13.5内存和性能

在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>

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 changed the document's title";
            break;
        case "goSomewhere":
            location.href = "http://www.wrox.com";
            break;
        case "sayHi":
            alert("hi");
            break;
    }
});

如果可行的话,也可以考虑为document对象添加一个事件处理程序,

用以处理页面上发生的某种特定类型的事件;这样做与采取传统的做法相比具有如下优点:

1.document对象很快就可以访问,而且可以在页面生命周期的任何时点上为它添加事件处理程序,

无需等待DOMContentLoaded或load事件;换句话说,只要可单击的元素呈现在页面上,就可以立即具备适当的功能;

2.在页面中设置事件处理程序所需的时间更少;

只添加一个事件处理程序所需的DOM引用更少,所花的时间也更少;

3.整个页面占用的内存空间更少,能够提升整体性能;

最适合采用事件委托技术的事件包括:

click,mousedown,mouseup,keydown,keyup,keypress;

虽然mouseover和mouseout事件也冒泡,但要适当处理它们并不容易,而且经常需要计算元素的位置;

因为当鼠标从一个元素移到其子节点时,或者当鼠标移出该元素时,都会触发mouseout事件;

移除事件处理程序

除了减少连接数量,还可以适时移除;

在两种情况下,可能会造成上述问题;

第一种情况就是从文档中移除带有事件处理程序的元素时;

这可能是通过纯粹的DOM操作,例如使用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>

在事件处理程序中删除按钮也能阻止事件冒泡;目标元素在文档中是事件冒泡的前提;

采用事件委托也有助于解决这个问题;

如果事先知道将来有可能使用innerHTML替换掉页面中的某一部分,

那么就可以不直接把事件处理程序添加到该部分的元素中;

而通过把事件处理程序指定给较高层次的元素,同样能够处理该区域中的事件;

导致”空事件处理程序”的另一种情况,就是卸载页面的时候;

毫不奇怪,IE8及更早版本在这种情况下依然是问题最多的浏览器,尽管其他浏览器或多或少也有类似的问题;

是的原文是这么说的233

一般来说,最好的做法是在页面卸载之前,先通过onunload事件处理程序移除所有事件处理程序;

13.6 模拟事件

也就是模拟事件触发;

DOM中的事件模拟

createEvent(),接收一个参数,即表示要创建的事件类型的字符串;

这个字符串可以是下列几字符串之一;

1.UIEvents:一般化的UI事件;鼠标事件和键盘事件都继承自UI事件;DOM3级中是UIEvent;

2.MouseEvents:一般化的鼠标事件;DOM3级中是MouseEvent;

3.MutationEvents:一般化的DOM变动事件;DOM3级中是MutationEvent;

4.HTMLEvents:一般化的HTML事件;没有对应的DOM3级事件,HTML事件被分散到其他类别中;

触发事件dispatchEvent();

模拟鼠标事件

创建鼠标事件对象的方法是为createEvent()传入字符串”MouseEvents”;

返回的对象有一个名为initMouseEvent()方法,用于指定与该鼠标事件有关的信息;

这个方法接收15个参数,是的,15个;

type,bubbles,cancelable,view,detail,screenX,screenY,clientX,clientY,

ctrlKey,altKey,shiftKey,metaKey,button,relatedTarget;

例子;

var btn = document.getElementById("myBtn");
//创建事件对象
var event = document.createEvent("MouseEvents");
//初始化事件对象
event.initMouseEvent("click", true, true, document.defaultView, 0, 0, 0, 0, 0,
                    false, false, false, false, 0, null);
//触发事件
btn.dispatchEvent(event);

模拟键盘事件

DOM3级规定,调用createEvent()并传入”KeyboardEvent”就可以创建一个键盘事件;

返回的事件对象会包含一个initKeyEvent()方法,这个方法接收下列参数;

type,bubbles,cancelable,view,key,location,modifiers,repeat;

由于DOM3级不提倡使用keypress事件,因此只能利用这种技术来模拟keydown和keyup事件;

var textbox = document.getElementById("myTextbox");
//以DOM3 级方式创建事件对象
if (document.implementation.hasFeature("KeyboardEvents", "3.0")){
    event = document.createEvent("KeyboardEvent");
    //初始化事件对象
    event.initKeyboardEvent("keydown", true, true, document.defaultView, "a",
                            0, "Shift", 0);
}
//触发事件
textbox.dispatchEvent(event);

这个例子模拟的是按住Shift的同时又按下A键;

要先检测是否支持DOM3,大部分浏览器返回的KeyboardEvent对象是非标准的;

模拟其他事件

模拟变动事件;

var event = document.createEvent("MutationEvents");
event.initMutationEvent("DOMNodeInserted", true, false, someNode, "","","",0);
target.dispatchEvent(event);

initMutationEvent()接收的参数:type,bubbles,cancelable,relatedNode,preValue,newValue,attrName,attrChange;

模拟HTML事件;

var event = document.createEvent("HTMLEvents");
event.initEvent("focus", true, false);
targ et.dispatchEvent(event);

浏览器中很少使用变动事件和HTML事件,因为使用它们会受到一些限制;

自定义DOM事件

DOM3中定义了createEvent(“CustomEvent”),返回一个initCustomEvent()的方法,

接收四个参数:type,bubbles,cancelable,detail;

例子:

var div = document.getElementById("myDiv"),
    event;
EventUtil.addHandler(div, "myevent", function (event) {
    alert("DIV: " + event.detail);
});
EventUtil.addHandler(document, "myevent", function (event) {
    alert("DOCUMENT: " + event.detail);
});
if (document.implementation.hasFeature("CustomEvents", "3.0")) {
    event = document.createEvent("CustomEvent");
    event.initCustomEvent("myevent", true, false, "Hello world!");
    div.dispatchEvent(event);
}

IE中的事件模拟

因为IE事件模拟与其他浏览器都不一样,所以本节solo;

例子;

var btn = document.getElementById("myBtn");
//创建事件对象
var event = document.createEventObject();
//初始化事件对象
event.screenX = 100;
event.screenY = 0;
event.clientX = 0;
event.clientY = 0;
event.ctrlKey = false;
event.altKey = false;
event.shiftKey = false;
event.button = 0;
//触发事件
btn.fireEvent("onclick", event);

createEventObject(),不接收参数,需要挨个设定,以及fireEvent();

键盘事件例子;

var textbox = document.getElementById("myTextbox");
//创建事件对象
var event = document.createEventObject();
//初始化事件对象
event.altKey = false;
event.ctrlKey = false;
event.shiftKey = false;
event.keyCode = 65;
//触发事件
textbox.fireEvent("onkeypress", event);

正如在DOM中模拟键盘事件一样,

运行这个例子也不会因模拟了keypress而在文本框中看到任何字符,

即使触发了事件处理程序也没有用;

emmm我好像只看到说DOM模拟键盘事件只触发keyup,keydown;

所以意思是,keypress直接无效吗……