Dom编程优化
对Dom的访问代价是昂贵,在富网页应用中通常是性能的瓶颈,所以对Dom的优化十分重要。
一.访问和修改Dom元素
浏览器通常要求JavaScript和Dom实现保持独立的。例如,在Internet Explorer 中,被称为JScript的JavaScript 实现位于库文件jscript.dll 中,而DOM 实现位于另一个库mshtml.dll(内部代号Trident)。所以用JavaScript访问Dom元素是需要一定的代价。人们通常这样形容Dom访问,javaScript和Dom相当于两个独立的小岛,这两个小岛中间有座桥连起来,JavaScript每次访问Dom都要过一次桥,过桥就要收取一定的过桥费。所以要尽量减少访问Dom的次数,那么如何做到呢?请看下面的例子。
function innerHTMLLoop() {
for (var count = 0; count < 15000; count++) {
document.getElementById('here').innerHTML += 'a';
}
}
上面这个函数的作用是对id是here这个Dom节点,进行了15000次修改,在这个函数中,对Dom节点进行了15000次访问。再看下面的函数。
function innerHTMLLoop() {
var text="";
for (var count = 0; count < 15000; count++) {
text+= 'a';
}
document.getElementById('here').innerHTML=text;
}
上面这个函数和第一个函数实现的是完全一样的功能,但是它对Dom的访问只有一次,性能是大大提高。
现在来比较一下document.createElement和innerHTML。
document.createElement是每次创建一个节点,然后加入到父节点中。innerHTML是用字符串拼接成一系列Dom节点然后在插入到目标节点中。如果在一个性能苛刻的操作中更新一大块HTML 页面,innerHTML 在大多数浏览器中执行更快。但对于大多数日常操作而言,其差异并不大,所以你应当根据代码可读性,可维护性,团队习惯,代码风格来综合决定采用哪种方法。
另外HTML集合用于存放Dom节点类数组对象,例如document.getElementsByTagName,getElementsByClass等函数得到的就是集合。它的使用也是非常昂贵的。考虑下面的例子
var alldivs = document.getElementsByTagName_r('div');
for (var i = 0; i < alldivs.length; i++) {
document.body.appendChild(document.createElement('div'))
}
上面的例子表面上是想倍增div的数量,但实际上是个死循环,因为div的长度是动态变化的,也就是说alldivs.length不是一个常量,它会每次根据div的数量变化,这样也就是每次要访问Dom节点,我们之前说过访问Dom的代价是昂贵的。所以最好的方法是将length用一个变量缓存起来,例如len=alldivs.length。
二.重绘和重排
我们都知道在页面刚加载的时候,浏览器会进行页面渲染,其实这就是一次绘制和排列的过程。绘制的是页面,排列的是Dom节点,一般来说绘制是根据color,background,opacity等css属性,而排列则根据width,height,margin,padding等能影响页面Dom元素位置变换的css属性。那么既然知道了什么是重绘和重排,就应该知道什么时候会重会和重排。也就是当你改变某些css属性时。
一般来说重排的影响是远大于重绘的,重排时浏览器会重新计算所有元素的位置和尺寸,重新排列。这个过程可以说是相当耗时间的,所以要尽量避免重排。考虑下面例子
var el = document.getElementById('mydiv');
el.style.borderLeft = '1px';
el.style.borderRight = '2px';
el.style.padding = '5px';
上面例子三次改变了el的css属性,而这三次都产生的重排。再看下面代码
var el = document.getElementById('mydiv');
el.style.cssText="border-left:1px;border-right:2px;padding:5px";
上面代码实现的是和第一例子一样的功能,但是它只产生的一次重排,大大提高了性能。
三.事件托管
当页面中存在大量元素,而且每个元素有一个或多个事件句柄与之挂接(例如onclick)时,可能会影响性能。连接每个句柄都是有代价的,无论其形式是加重了页面负担(更多的页面标记和JavaScript 代码)还是表现在运行期的运行时间上。所以事件托管是很有用的。
每个事件发生时会经历捕获,到达目标,冒泡,三个阶段。例如:
当用户点击了“menu #1”链接,点击事件首先被<a>元素收到。然后它沿着DOM 树冒泡,被<li>元素收到,然后是<ul>,接着是<div>,等等,一直到达文档的顶层,甚至window。如果需要在每个li上加监听事件,那么可以加到ul上,因为每次点击li都会冒泡到ul上。
总结:
DOM 访问和操作是现代网页应用中很重要的一部分。但每次你通过桥梁从ECMAScript 岛到达DOM 岛时,都会被收取“过桥费”。为减少DOM 编程中的性能损失,请牢记以下几点:
最小化DOM 访问,在JavaScript 端做尽可能多的事情
在反复访问的地方使用局部变量存放DOM 引用.
小心地处理HTML 集合,因为他们表现出“存在性”,总是对底层文档重新查询。将集合的length 属性缓存到一个变量中,在迭代中使用这个变量。如果经常操作这个集合,可以将集合拷贝到数组中。
注意重绘和重排版;批量修改风格,离线操作DOM 树,缓存并减少对布局信息的访问。
使用事件托管技术最小化事件句柄数量。
Dom编程优化的更多相关文章
- 性能优化之数据存储&DOM编程
多读书多看报 数据存储 ·在javascript中,数据存储的位置会对代码整体性能产生重大的影响. ·数据存储共有4种方式:字面量.变量.数组.对象成员. ·要理解变量的访问速度,就要理解作用域. ...
- JavaScript性能优化 DOM编程
最近在研读<高性能JavaScript>,在此做些简单记录.示例代码可在此处查看到. 一.DOM 1)DOM和JavaScript 文档对象模型(DOM)是一个独立于语言的,用于操作XML ...
- 《高性能javascript》 领悟随笔之-------DOM编程篇
<高性能javascript> 领悟随笔之-------DOM编程篇一 序:在javaSctipt中,ECMASCRIPT规定了它的语法,BOM实现了页面与浏览器的交互,而DOM则承载着整 ...
- 高性能JavaScript笔记一(加载和执行、数据访问、DOM编程)
写在前面 好的书,可能你第一遍并不能领会里面的精魂,当再次细细品评的时候,发现领悟的又是一层新的含义 (这段时间,工作上也不会像从前一样做起来毫不费力,开始有了新的挑战,现在的老大让我既佩服又嫉妒,但 ...
- 160826、浏览器渲染页面过程描述,DOM编程技巧以及重排和重绘
一.浏览器渲染页过程描述 1.浏览器解析html源码,然后创建一个DOM树. 在DOM树中,每一个HTML标签都有一个对应的节点(元素节点),并且每一个文本也都有一个对应的节点(文本节点). DO ...
- 浏览器渲染页面过程描述,DOM编程技巧以及重排和重绘。
一.浏览器渲染页过程描述 1.浏览器解析html源码,然后创建一个DOM树. 在DOM树中,每一个HTML标签都有一个对应的节点(元素节点),并且每一个文本也都有一个对应的节点(文本节点). DOM树 ...
- 《javascript dom编程艺术》笔记(一)——优雅降级、向后兼容、多个函数绑定onload函数
刚刚开始自学前端,如果不对请指正:欢迎各位技术大牛指点. 开始学习<javascript dom编程艺术>,整理一下学习到的知识.今天刚刚看到第六章,记下get到的几个知识点. 优雅降级 ...
- 高性能JavaScript之DOM编程
我们知道.DOM是用于操作XML和HTML文档的应用程序接口,用脚本进行DOM操作的代价非常昂贵. 有个贴切的比喻.把DOM和JavaScript(这里指ECMScript)各自想象为一个岛屿,它们之 ...
- 高性能Javascript(2) DOM编程
第三部分 DOM编程 文档对象模型(DOM)是一个独立于语言的,使用XML和HTML文档操作的应用程序接口(API).在浏览器中,主要与HTML文档打交道,在网页应用中检索XML文档也很常见.DOM ...
随机推荐
- HashMap的hash分析
哈希 Hash,一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入,通过散列算法,变换成固定长度的输出,该输出就是散列值.这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空 ...
- 初撩RESTful
1. 什么是RESTful? 一种软件架构风格,设计风格,用于客户端和服务端交互类的架构. 一组架构约束条件和原则 2. 什么是RESTful架构? 客户端通过http动词(get/post等)对服务 ...
- MySQL数据库操作:“增删改查”,忘记密码重置等。
[注] 数据库的“增删查改”,参考原作者Wid:http://www.cnblogs.com/mr-wid/archive/2013/05/09/3068229.html#d11.感谢大佬们的技术分享 ...
- mysql 100%占用的解决
早上客户反应,其网站无法访问,无限转圈 上服务器,查看磁盘空间df -h,内存使用率free -m,网络流量iftop均正常 然后使用top查看时,发现mysql的cpu使用率上升到200%. 解决过 ...
- set,get方法(属性,索引器)
很多时候我们不可以把一些字段暴露出来允许别人调用和修改,为了隐藏这些字段又便于加限制的使用,在面向对象编程中一般采用写get set函数的办法,比如: //字段_age, "_"表 ...
- java 居民身份证的校验
import java.text.SimpleDateFormat; import java.util.Date; /** * 验证身份证号码 身份证号码, 可以解析身份证号码的各个字段, * 以及验 ...
- js——private 私有方法公有化
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 汇编检测OD代码
repnz指令说明:重复执行其后面的指令,CX或ECX存放最多比较次数,DI或EDI存放查找表首地址,AL或AX或EAX存放想查找的内容.当(CX或ECX)= 0 或 ZF=1 退出重复,否则,(CX ...
- [NOIP模拟测试11] 题解
A.string 和河北的一道省选题很像.考场上写的暴力桶排,正解其实就是优化一下这个思路. 开线段树维护字符串中每个字母出现的次数.对于每条询问,区间查询.区间赋值维护即可. 另外,本题卡常严重,正 ...
- bzoj1211树的计数 x bzoj1005明明的烦恼 题解(Prufer序列)
1211: [HNOI2004]树的计数 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 3432 Solved: 1295[Submit][Stat ...