增加JavaScript性能之优化文档对象的操作

来源:互联网 发布:期货玻璃手续费的算法 编辑:程序博客网 时间:2024/06/07 08:55
优化文档对象的操作
导致大多数网站和应用程序出现性能缓滞的一个最大因素是通过JavaScript低效访问HTML页面元素。因为所有浏览器的JavaScript引擎独立于其他渲染引擎,通过JavaScript获取对页面元素的引用要涉及从一个引擎跳转到另一个引擎,浏览器则充当了两者之间的中介。为了提高性能,我们需要减少这种跳转所出现的次数。这里列举了若干技巧来帮助我们避免一些JavaScript对HTML页面元素的不必要的访问。

实现对页面元素的最小化访问

(1)以变量保存对DOM元素的引用以便后续使用,如下代码所示:
var header = document.getElementById("header"),nav = document.getElementById("nav");header.className += "" + nav.className;

(2)通过对单独父元素的引用来访问其子DOM元素,如下代码所示:
var wrapper = document.getElementById("wrapper"),    header = wrapper.getElementByTagName("header")[0],    nav = wrapper.getElementByTagName("nav")[0];header.className += "" + nav.className;

(3)对新建元素实施DOM修改操作后才将其添加至当前实时页面,如下代码所示:
var list = document.createElement("ul"),    listItem = document.createElement("li"),//先在JavaScript中尽可能的实施所有的DOM操作listItem.innerHTML = "I am a listItem";list.appendChild(listItem);//最后,当你确定不再需要做任何修改时再把该元素添加到页面进行显示document.body.appendChild(list);

尽量利用已有元素

在网站和应用程序中,动态的创建DOM元素是一个相当普遍的需求,但每一次使用标准的document.createElement()方法来创建元素以及用类似的方法将其配置到已经存在的元素之上都会带来性能上的损失。为了提高性能,可以复制已经存在的元素,而不是重新建立新的元素。复制已经存在的元素以提高性能,如下代码所示:
var list1 = document.createElement("ul"),    list2,    listItem1 = document.createElement("li"),    listItem2,    listtItem3;listItem1.className = "list-item";listItem1.innerHTML = "I am a list item";//cloneNode方法可以高效的复制元素,将其可选参数设为true,则会复制该元素及其属下的所有子元素//(相关的对象属性也会复制)。不填写该参数或设为false,则会只复制该元素本身listItem2 = listItem1.cloneNode(true);listItem3 = listItem1.cloneNode(true);//添加该列表项至该无序列表元素list1.appendChild(listItem1);list1.appendChild(listItem2);list1.appendChild(listItem3);//复制整个无序列表list2 = list1.cloneNode(true);//把这两个一模一样的无序列表元素添加至实时页面document.body.appendChild(list1);document.body.appendChild(list2);

离线DOM的利用

除了在JavaScript中不断地访问实时页面来创建和管理元素,我们可以使用DOM规范,即文档片段(document fragment),或称为离线DOM(offline DOM),这是一个轻量级版本的DOM,用于创建和操作小型的元素树结构以在稍后将其添加至当前实时页面。比起使用实时页面的DOM,使用这项技术来操控元素可以获得更佳的性能。如下代码所示:
//创建一个DocumentFragment对象作为离线DOM结构,不用实时DOM交互var offlineDOM = document.createDocumentFragment(),//创建各个将用于动态的添加至页面中的元素    header = document.createElement("header"),    nav = document.createElement("nav");//将每个元素添加到离线DOM上offlineDOM.appendChild(header);offlineDOM.appendChild(nav);//将离线DOM的一份副本添加至当前实时页面document.body.appendChild(offlineDOM);

PS:appendChild添加的是offlineDOM中的内容。offlineDOM本身不会存在于页面中

使用CSS而非JavaScript来操控页面样式

可以通过DOM来直接操控CSS样式属性,方法是使用元素的style属性来实现,但这会影响它的布局,从而在浏览器中引发一次重排(reflow,为了渲染部分或整个页面,浏览器重新计算页面元素位置和几何结构的进程叫做重排)。重排需要时间,并且接下来还要处理多个style属性,会导致更多不必要的重排。如下代码所示:

var nav = document.getElementByTagName("nav");nav.style.backgrooundColor = "#000";//在浏览器中引发一次重排nav.style.color = "#fff";//引发一次重排nav.style.opacity = 0.5;//引发一次重排

处理这个问题有两个解决方案。

第一种是通过JavaScript而非单独的样式应用一个CSS 类至页面元素。这使得所有的CSS规则一次性的同时应用至该元素,而且只引发一次重排。
应用CSS类至DOM元素以减少浏览器重排,如下代码所示:
var nav = document.getElementByTagName("nav");nav.classNmae += "selected";//名称为"selected"的CSS类中包含着多项样式设定

第二种是先设置display属性为none,再进行其他样式属性的修改。这会从页面流中移除该元素的可视显示,并引发一次浏览器重排,但这也意味着当该元素离开页面流后的其他任何样式属性的修改都不会再引发浏览器重排。一旦修改操作完成后,应该通过设置该属性的display属性为block或其他可设置值来把该元素重新放回页面流中。
隐藏元素并修改元素的style属性,以此来减少浏览器重排的发生,代码如下:
var nav = document.getElementByTagName("nav");nav.style.display = "none";//隐藏元素不让其显示,引发一次浏览器重排nav.style.backgrooundColor = "#000";//因为元素已隐匿不会引发浏览器重排nav.style.color = "#fff";//不会引发浏览器重排nav.style.opacity = 0.5;//不会引发浏览器重排nav.style.display = "block";//使该元素重新显示,引发一次浏览器重排

原创粉丝点击