文档对象模型(DOM)用于操作XML和HTML文档的应用程序接口,与语言无关。
各浏览器中DOM和javascript独立实现,如表
浏览器 | DOM | javascript |
IE | Trident(mshtml.dll) | JScript(jscript.dll) |
Safari | Webkit中的WebCore | JavaScriptCore(最新版叫SquirrelFish) |
Webkit中的WebCore | V8 | |
Firefox | Gecko | SpiderMonkey(最新版叫TraceMonkey) |
DOM和javascript(ECMAScript)通过接口连接,所以访问和修改DOM会影响性能。
innerHTML:
document.getElementById("aaa").innerHTML="
DOM:
var tr = document.CreateElement("tr"); var td=document.CreateElement("td"); td.appendChild(document.createTextNode('aaa')); tr.appendChild(td); td=document.createElement("td"); var a=document.createElement("a"); a.setAttribute("href","http://baidu.com"); td.appendChild(a); tr.appendChild(td);
上面两种方式生成html的性能比较,innerHTML的优势在老版本浏览器中很明显,只有基于WebKit内核的新版浏览器中DOM方法略胜。
更新一大段HTML推荐使用innerHTML。
创建重复的元素时,第一个用document.createElement,后面的用 tr.cloneNode(false)速度会略快一点点。
HTML集合包括:
document.getElementsByName();
document.getElementsByClassName();
document.getElementsByTagName();
document.images
document.links
document.forms
document.forms[0].elements
html集合是类似数组的列表(没有push()或slice()之类的方法所以不是数组)。但是能以数字索引的方式访问列表中的元素,还有length属性。
html集合非常低效,因为它是实时和文档保持一致的,包括访问length属性都会重复执行查询的过程。
比如下面的就是一个死循环
var alldivs=document.getElementsByTagName("div"); for(var i=0;i
一般解决上面性能慢的方式,是设置一个集合,并把它拷贝到一个数组中,下面的可为通用转换函数:
function toArray(coll){ for(var i=0, a=[],len=coll.length;i
在DOM中爬行,也就是从某个DOM元素开始操作周围的元素,或者递归查找所有的子节点,建议使用nextSibling,别用childNodes
下面表格中建议用第一列的DOM属性,
性能好的属性名 | 被替换的属性名 |
children | childNodes |
childElementCount | childNodes.length |
firstElementChild | firstChild |
lastElementChild | lastChild |
nextElementSibling | nextSibling |
previousElementSibling | previousSibling |
querySelectorAll方法:可进行组合查询。此种方法反回的是数组对象,不是html集合,因此返回的节点不会对应实时的文档结构,避免了html集合引起的性能问题。支持的浏览器有IE8,Firefox3.5,Safari3.1,Chrome1,Opera.
var elements = document.querySelectorAll("#menu a");
浏览器下载完页面以后生成两个结构 DOM树和渲染树(渲染树中的节点称帧frames或盒boxes)
按css模型的定义,页面元素为具有填充(padding),边距(margins),边框(borders)和位置(position)的盒子。
浏览器显示的顺序:下载页面--构建DOM树和渲染树--显示(绘制paint)页面元素
当DOM的变化影响了元素的几何属性(宽和高),浏览器会使渲染树中受到影响的部分失效,并重新构造渲染树,即重排reflow,重排后会重新绘制受影响部分到屏幕中,即重绘repaint
重排影响性能。重排在下面情况时会发生:添加或删除可见的DOM元素,元素位置改变,元素尺寸改变,内容改变,页面渲染器初始化,浏览器窗口尺寸改变。
浏览器通过队列化优化重排。但是下面的属性和方法需要返回最新的布局信息,所以会触发重排。
offsetTop,offsetLeft,offsetWidth,offsetHeigth
scrollTop,scrollLeft,scrollWidth,scrollHeigth
clientTop,clientLeft,clientWidth,clientHeigth
getComputedStyle() //这个是在IE、Opera中
在修改样式的过程中,最好避免使用上面列出的属性。
减少能引起重排的操作,合并所有的改变最后一次处理,可使用cssText属性实现或改变css的class名称实现:
var el=document.getElementById("mydiv"); el.style.cssText="border-left:1px;border-right:2px;padding:5px;";
el.className="active";//改变类时需要检查级联样式,有轻微的性能影响
1,通过改变display属性,临时从文档中移除,做了所有的修改以后再恢复。这样最多只会更改DOM两次。
var ul=document.getElementById("mylist"); ul.style.display="none"; //这里可进行对mylist的任意多次修改 ul.style.display="block";
2,在文档之外更新一个文档片断,然后把它附加到原始列表中。只触发一次重排。
var fragment=document.createDocumentFragment(); //这里可进行任意修改 document.getElementById("mylist").appendChild(fragment);//附加一个片断到节点中时,实际上被添加的是该片断的子结点。
3,为需要修改的节点创建一个备份,修改完后再替代旧的节点。
var old=document.getElementById("mylist"); var clone=old.cloneNode(true); //修改 old.parentNode.replaceChild(clone,old);
少使用:hover这个CSS伪选择器。特别是在IE8中最影响性能。
页面中存在大量元素,并且其中很多元素都需要绑定事件处理器(onclick等),可能会影响性能。可以在用冒泡方式在父级元素捕获。
document.getElementById("parent").οnclick=function(e){ //假设parent是父元素,它含有很多子元素。 //浏览器target e=e||window.event; var target =e.target||e.srcElement; var pageid,hrefparts; //只关心hrefs,非链接点击则退出。这个示例中只演示捕获parent中子节点是A标签的情况 if(target.nodeName!=="a"){ return; } //从链接中找出页面ID hrefparts=target.href.split("/"); pageid=hrefparts[hrefparts.length-1]; pageid=pageid.replace(".html",""); //更新页面 ajaxRequest("xhr.php?page="+id,updatePageContents); //浏览器组织默认行为并取消冒泡 if(typeof e.preventDefault==="function"){ e.preventDefault(); e.stopPropagation(); }else{ e.returnValue=false; e.cancelBubble=true; } };