第三部分 DOM编程

文档对象模型(DOM)是一个独立于语言的,使用XML和HTML文档操作的应用程序接口(API)。在浏览器中,主要与HTML文档打交道,在网页应用中检索XML文档也很常见。DOM APIs主要用于访问这些文档中的数据。尽管DOM是与语言无关的API,在浏览器中的接口却是以JavaScript实现的。客户端大多数脚本程序与文档打交道,DOM就成为JavaScript代码日常行为中重要的组成部分。

2.1 DOM Access and Modification  DOM访问和修改

简单来说,正如前面所讨论的那样,访问一个DOM元素的代价就是交一次“过桥费”。修改元素的费用可能更贵,因为它经常导致浏览器重新计算页面的几何变化.如下面的例子:

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

此函数在循环中更新页面内容。这段代码的问题是,在每次循环单元中都对DOM元素访问两次:一次读取innerHTML属性能容,另一次写入它。因此,快捷的方法是生成完整的字符串以后一次性的对DOM元素进行修改和访问。

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

这些结果清楚地表明,访问DOM越多,代码的执行速度就越慢。因此,一般经验法则是:轻轻地触摸DOM,并尽量保持在ECMAScript范围内。

2.2 innerHTML Versus DOM methods  innerHTML与DOM方法比较

多年来,在web开发者社区已经对此问题进行了许多讨论:更新页面时,使用虽不标准却被良好支持的innerHTML属性更好呢,还是使用纯DOM方法,document.createElement ()更好呢?如果不考虑标准问题,它们的性能如何?答案是:性能差别不大,但是,在所有浏览器中,innerHTML速度更快一些,除了最新的基于WebKit的浏览器。

function tableInnerHTML() {
var i, h = ['<table border="1" width="100%">'];
h.push('<thead>');
h.push('<tr><th>id<\/th><th>yes?<\/th><th>name<\/th><th>url<\/th><th>action<\/th><\/tr>');
h.push('<\/thead>');
h.push('<tbody>');
for (i = 1; i <= 1000; i++) {
h.push('<tr><td>');
h.push(i);
h.push('<\/td><td>');
h.push('And the answer is... ' + (i % 2 ? 'yes' : 'no'));
h.push('<\/td><td>');
h.push('my name is #' + i);
h.push('<\/td><td>');
h.push('<a href="http://example.org/' + i + '.html">http://example.org/' + i + '.html<\/a>');
h.push('<\/td><td>');
h.push('<ul>');
h.push(' <li><a href="edit.php?id=' + i + '">edit<\/a><\/li>');
h.push(' <li><a href="delete.php?id="' + i + '-id001">delete<\/a><\/li>');
h.push('<\/ul>');
h.push('<\/td>');
h.push('<\/tr>');
}
h.push('<\/tbody>');
h.push('<\/table>');
document.getElementById('here').innerHTML = h.join('');
};

上面的例子描述了用innerHTML进行生成元素的方式。我们在这里只是记住这几个基本方式就可以了。

2.3 Cloning Nodes 节点克隆

2.4 HTML Collections  HTML集合

HTML集合是用于存放DOM节点引用的类数组对象。下列函数的返回值就是一个集合:
     • document.getElementsByName()
     • document.getElementsByClassName()
     • document.getElementsByTagName_r()

下列属性也属于HTML集合:

  • document.images页面中所有的<img>元素
  • document.links 所有的<a>元素
  • document.forms 所有表单
  • document.forms[0].elements页面中第一个表单的所有字段

这些方法和属性返回HTMLCollection对象,是一种类似数组的列表。它们不是数组(因为它们没有诸如push()或slice()之类的方法),但是提供了一个length属性,和数组一样你可以使用索引访问列表中的元素。

2.4 Expensive collections 昂贵的集合

正如在第四章中将要讨论的,不建议用数组的length属性做循环判断条件。访问集合的length比数组的length还要慢,因为它意味着每次都要重新运行查询过程.

在下面的例子中,在循环中访问每个元素的三个属性。最慢的版本每次都要访问全局的document,优化后的版本缓存了一个指向集合的引用,最快的版本将集合的当前元素存入局部变量。所有三个版本都缓存了集合的length属性。

// 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;
};

关于DOM的操作可提高性能的地方有很多,例如访问兄弟节点和子节点等等。

2.5 The Selectors API 选择器API

识别DOM中的元素时,开发者经常需要更精细的控制,而不仅是getElementById()和getElementsByTagName_r()之类的函数。有时你结合这些函数调用并迭代操作它们返回的节点,以获取所需要的元素,这一精细的过程可能造成效率低下.另一方面,使用CSS选择器是一个便捷的确定节点的方法,因为开发者已经对CSS很熟悉了。许多
JavaScript库为此提供了API,而且最新的浏览器提供了一个名为querySelectorAll()的原生浏览器DOM函数。显然这种方法比使用JavaScript和DOM迭代并缩小元素列表的方法要快。如下所示:

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

elements的值将包含一个引用列表,指向那些具有id="menu"属性的元素。函数querySelectorAll()接收一个CSS选择器字符串参数并返回一个NodeList——由符合条件的节点构成的类数组对象。此函数不返回HTML集合,所以返回的节点不呈现文档的“存在性结构”。这就避免了本章前面提到的HTML集合所固有的性能问题(以及潜在的逻辑问题)。

如果不使用querySelectorAll(),达到同样的目标的代码会冗长一些:
var elements = document.getElementById('menu').getElementsByTagName_r('a');

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

Summary

DOM访问和操作是现代网页应用中很重要的一部分。但每次你通过桥梁从ECMAScript岛到达DOM岛
时,都会被收取“过桥费”。为减少DOM编程中的性能损失,请牢记以下几点:

• Minimize DOM access, and try to work as much as possible in JavaScript.
最小化DOM访问,在JavaScript端做尽可能多的事情。
• Use local variables to store DOM references you'll access repeatedly.
在反复访问的地方使用局部变量存放DOM引用.
• Be careful when dealing with HTMLcollections because theyrepresent the live, underlying document. Cache
the collection lengthinto a variable and use it when iterating, and make a copy of the collection into an array for
heavy work on collections.
小心地处理HTML集合,因为他们表现出“存在性”,总是对底层文档重新查询。将集合的length属性缓
存到一个变量中,在迭代中使用这个变量。如果经常操作这个集合,可以将集合拷贝到数组中。
• Use faster APIs when available, such as querySelectorAll() and firstElementChild.
如果可能的话,使用速度更快的API,诸如querySelectorAll()和firstElementChild。
• Be mindful of repaints and reflows; batch style changes, manipulate the DOM tree "offline," and cache and
minimize access to layout information.
注意重绘和重排版;批量修改风格,离线操作DOM树,缓存并减少对布局信息的访问。
• Position absolutely during animations, and use drag and drop proxies.

动画中使用绝对坐标,使用拖放代理。
• Use event delegation to minimize the number of event handlers.
使用事件托管技术最小化事件句柄数量

高性能Javascript(2) DOM编程的更多相关文章

  1. 高性能JavaScript之DOM编程

    我们知道.DOM是用于操作XML和HTML文档的应用程序接口,用脚本进行DOM操作的代价非常昂贵. 有个贴切的比喻.把DOM和JavaScript(这里指ECMScript)各自想象为一个岛屿,它们之 ...

  2. 高性能JavaScript(DOM编程)

    首先什么是DOM?为什么慢? DOM:文档对象模型,是一个独立于语言的,用于操作XML和HTML文档的程序接口(API) 用脚本进行DOM操作的代价很昂贵.那么,怎样才能提高程序的效率? 1.DOM访 ...

  3. HTML、css、javascript、DOM编程

    HTML.css.javascript.DOM编程 一.Html 1.1html概述 Html就是超文本标记语言的简写,是最基础的网页语言,其代码都是由标签所组成,是通过标签来定义的语言,代码不需要区 ...

  4. JavaScript的DOM编程--12--innerHTML属性

    innerHTML属性: 1). 浏览器几乎都支持该属性, 但不是 DOM 标准的组成部分. innerHTML 属性可以用来读, 写某给定元素里的 HTML 内容 <html> < ...

  5. JavaScript的DOM编程--01--js代码的写入位置

    DOM:Document Object Model(文本对象模型) D:文档 – html 文档 或 xml 文档 O:对象 – document 对象的属性和方法 M:模型 DOM 是针对xml(h ...

  6. JavaScript的DOM编程--11--插入节点

    插入节点: 1). insertBefore(): 把一个给定节点插入到一个给定元素节点的给定子节点的前面 var reference = element.insertBefore(newNode,t ...

  7. JavaScript的DOM编程--10--删除节点

    1). removeChild(): 从一个给定元素里删除一个子节点 var reference = element.removeChild(node); 返回值是一个指向已被删除的子节点的引用指针. ...

  8. JavaScript的DOM编程--09--节点的替换

    节点的替换: 1). replaceChild(): 把一个给定父元素里的一个子节点替换为另外一个子节点 var reference = element.replaceChild(newChild,o ...

  9. JavaScript的DOM编程--08--复习

    <html> <head> <meta http-equiv="Content-Type" content="text/html; char ...

随机推荐

  1. JDK和CGLIB生成动态代理类的区别

     关于动态代理和静态代理 当一个对象(客户端)不能或者不想直接引用另一个对象(目标对象),这时可以应用代理模式在这两者之间构建一个桥梁--代理对象. 按照代理对象的创建时期不同,可以分为两种: 静态代 ...

  2. ubuntu16.04下搜狗输入法异常

    问题描述: 搜狗输入法出现异常, 提示: 删除 .config/Sougou-PY 文件后重启 解决方案: google后发现,搜狗拼音输入法使用 fcitx 框架. 发现系统同时安装了ibus框架 ...

  3. POJ2115 C Looooops 扩展欧几里德

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - POJ2115 题意 对于C的for(i=A ; i!=B ;i +=C)循环语句,问在k位存储系统中循环几次 ...

  4. 动态产生DataSource------待整理

    1. https://www.cnblogs.com/wsss/p/5475057.html https://www.cnblogs.com/jiligalaer/p/5418874.html htt ...

  5. 090实战 Hadoop离线项目介绍(不包括程序)

    一:项目场景 1.需求分析 根据用户行为数据进行程序的处理,得到结果保存到关系型数据库中 需要收集用户(系统使用者)在不同客户端上产生的用户行为数据,最终保存到hdfs上 需要明确收集字段的相关信息, ...

  6. eric6中ui文件编译失败,提示找不到puicc5

    1解决办法 在setting中——preference 找到qt设置——pyQT工具文件选择更改为: 我的pyuicc5.exe文件在这个目录下 然后右击编译窗口,就成功了. 如果找不到ui文件,在窗 ...

  7. Python String 方法详解

    官网文档地址:https://docs.python.org/3/library/stdtypes.html#string-methods 官网 公号:软测小生ruancexiaosheng 文档里的 ...

  8. python tkinter-单选、多选

      单选按钮 tkinter.Radiobutton(root,text='a').pack() tkinter.Radiobutton(root,text='b').pack() tkinter.R ...

  9. python爬虫学习(一):BeautifulSoup库基础及一般元素提取方法

    最近在看爬虫相关的东西,一方面是兴趣,另一方面也是借学习爬虫练习python的使用,推荐一个很好的入门教程:中国大学MOOC的<python网络爬虫与信息提取>,是由北京理工的副教授嵩天老 ...

  10. 卡特兰数 Catalan 笔记

    一.公式 卡特兰数一般公式 令h(0)=1,h(1)=1,catalan数满足递推式.h(n) = h(0)*h(n-1)+h(1)*h(n-2) + ... + h(n-1)h(0) (n>= ...