首页 > 编程语言 > 详细

高性能javascript(第三章 DOM编程)

时间:2014-09-09 17:43:29      阅读:254      评论:0      收藏:0      [点我收藏+]

1、浏览器之DOM

浏览器通常要求 DOM 实现和 JavaScript 实现保持相互独立

这对性能意味着什么呢?简单说来,两个独立的部分以功能接口连接就会带来性能损耗。一个很形象的 比喻是把 DOM 看成一个岛屿,把 JavaScript(ECMAScript)看成另一个岛屿,两者之间以一座收费桥连接

每次 ECMAScript 需要访问DOM 时,你需要过桥,交一次“过桥费”。你操作 DOM 次数越多,费用就越高。一般的建议是尽量减少过桥次数,努力停留在 ECMAScript 岛上。本章将对此问题给出详细解答,告诉你应该关注什么地方, 以提高用户交互速度。

 

2、DOM访问和修改

  访问一个 DOM 元素的代价就是交一次“过桥费”。修改元素的费用可能更贵,因为它经常导致浏览器重新计算页面的几何变化

function innerHTMLLoop() {
for (var count = 0; count < 15000; count++) {
document.getElementById(‘here‘).innerHTML += ‘a‘;

  上面这段代码对dom访问了两次一次读取它,另外一次写入它

  改进:

  

function innerHTMLLoop2() {
    var content = ‘‘;
    for (var count = 0; count < 15000; count++) {
        content += ‘a‘;
    }
    document.getElementById(‘here‘).innerHTML += content;
}

  一般经验法则是:轻轻地触摸 DOM,并尽量保持在 ECMAScript 范围内。

 

3、innerHTML 与 DOM 方法比较

  使用innerHTML创建1000*5的表:

  使用 DOM 方法创建同样的表:

  其实这两种方式在新版的浏览器上差别不是很大

 

4、使用节点克隆,一般会快2%~10%;

5、HTML集合:

  死循序:

    var alldivs = document.getElementsByTagName_r(‘div‘);
    for (var i = 0; i < alldivs.length; i++) {
        document.body.appendChild(document.createElement(‘div‘))
    }

  看下面三种不同的访问方式:

    function toArray(coll) {
        for (var i = 0, a = [], len = coll.length; i < len; i++) {
            a[i] = coll[i];
        }
        return a;
    }

    var coll = document.getElementsByTagName_r(‘div‘);
    var arr = toArray(coll);
//slower
    function loopCollection() {
        for (var count = 0; count < coll.length; count++) {
        }
    }

// faster
    function loopCopiedArray() {
        for (var count = 0; count < arr.length; count++) {
        }
    }
//缓存  跟loopCopiedArray差不多一样快
    function loopCacheLengthCollection() {
        var coll = document.getElementsByTagName_r(‘div‘), len = coll.length;
        for (var count = 0; count < len; count++) {
        }
    }

6、访问集合元素时使用局部变量(缓存):

  三种缓存方式的比较如下代码:

// slow
function collectionGlobal() {
    var coll = document.getElementsByTagName_r(‘div‘), len = coll.length,
        name = ‘‘;
    for (var count = 0; count < len; count++) {
        name = document.getElementsByTagName_r(‘div‘)[count].nodeName;
        name = document.getElementsByTagName_r(‘div‘)[count].nodeType;
        name = document.getElementsByTagName_r(‘div‘)[count].tagName;
    }
    return name;
};
// faster
function collectionLocal() {
    var coll = document.getElementsByTagName_r(‘div‘), len = coll.length,
        name = ‘‘;
    for (var count = 0; count < len; count++) {
        name = coll[count].nodeName;
        name = coll[count].nodeType;
        name = coll[count].tagName;
    }
    return name;
};
// fastest
function collectionNodesLocal() {
    var coll = document.getElementsByTagName_r(‘div‘), len = coll.length,
        name = ‘‘,
        el = null;
    for (var count = 0; count < len; count++) {
        el = coll[count];
        name = el.nodeName;
        name = el.nodeType;
        name = el.tagName;
    }
    return name;
};
7、遍历dom tree:使用childNode集合或使用nextSibling两种方式的比较:
  在不同的浏览器上,这两种方式的运行时间基本相同:
//nextSibling方式
function testNextSibling() {
    var el = document.getElementById(‘mydiv‘), ch = el.firstChild,
        name = ‘‘;
    do {
        name = ch.nodeName;
    } while (ch = ch.nextSibling);
    return name;
};
// nodeName方式
function testChildNodes() {
    var el = document.getElementById(‘mydiv‘), ch = el.childNodes,
        len = ch.length,
        name = ‘‘;
    for (var count = 0; count < len; count++) {
        name = ch[count].nodeName;
    }
    return name;
};

 

8、只表示元素节点的DOM属性(HTML标签)和表示所有节点的属性如下表:一般情况下只表示元素节点的dom要快些

bubuko.com,布布扣

 

9、选择器API

var elements = document.querySelectorAll(‘#menu a‘);

  elements 的值将包含一个引用列表,指向那些具有 id="menu"属性的元素。函数 querySelectorAll()接收 一个 CSS 选择器字符串参数并返回一个 NodeList——由符合条件的节点构成的类数组对象。此函数不返回 HTML 集合,所以返回的节点不呈现文档的“存在性结构”。

  这就避免了本章前面提到的 HTML 集合所固有 的性能问题(以及潜在的逻辑问题)。

 

var elements = document.getElementById(‘menu‘).getElementsByTagName_r(‘a‘);

  这种情况下 elements 将是一个 HTML 集合,所以你还需要将它拷贝到一个数组中,如果你想得到与 querySelectorAll()同样的返回值类型的话。

 

对于下面两段代码,使用选择器API比对手快2~6倍

//使用选择器API
var errs = document.querySelectorAll(‘div.warning, div.notice‘);
//使用一般方法
var errs = [],
    divs = document.getElementsByTagName_r(‘div‘),
    classname = ‘‘;
for (var i = 0, len = divs.length; i < len; i++) {
    classname = divs[i].className;
    if (classname === ‘notice‘ || classname === ‘warning‘) {
        errs.push(divs[i]);
    }
}

 


 

10、重绘和重排版

当浏览器下载完所有页面 HTML 标记,JavaScript,CSS,图片之后,它解析文件并创建两个内部数据结构:

   一棵DOM树:表示页面结构

   一棵渲染树:表示 DOM 节点如何显示

渲染树中为每个需要显示的 DOM 树节点存放至少一个节点(隐藏 DOM 元素在渲染树中没有对应节点)。渲染树上的节点称为“框”或者“盒”,符合 CSS 模型的定义,将页面元素看作一个具有填充、边距、 边框和位置的盒。

一旦 DOM 树和渲染树构造完毕,浏览器就可以显示(绘制)页面上的元素了。

 

当 DOM 改变影响到元素的几何属性(宽和高)——例如改变了边框宽度或在段落中添加文字,将发生一系列后续动作——浏览器需要重新计算元素的几何属性,而且其他元素的几何属性和位置也会因此改变受到影响。

浏览器使渲染树上受到影响的部分失效,然后重构渲染树。这个过程被称作重排版。重排版完成时,浏览器在一个重绘进程中重新绘制屏幕上受影响的部分。

不是所有的 DOM 改变都会影响几何属性。例如,改变一个元素的背景颜色不会影响它的宽度或高度。 在这种情况下,只需要重绘(不需要重排版),因为元素的布局没有改变。

 

 

 

 

 

高性能javascript(第三章 DOM编程)

原文:http://www.cnblogs.com/liguwe/p/3962741.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!