JavaScript性能优化 DOM编程
最近在研读《高性能JavaScript》,在此做些简单记录。示例代码可在此处查看到。
一、DOM
1)DOM和JavaScript
文档对象模型(DOM)是一个独立于语言的,用于操作XML和HTML文档的程序接口(API)。
浏览器通常会把DOM和JavaScript独立实现。例如Chrome中使用Webkit的WebCore库渲染页面,用V8作为JavaScript引擎。
访问DOM天生就慢,将DOM和JavaScript比喻为两个岛屿,两处同行要收过桥费,ECMAScript访问DOM的次数越多,过桥费越贵,因此推荐的做法是尽可能减少过桥的次数。
2)性能测试
下图是对两段代码的性能测试,可在此处查看在线性能测试。
1. 第一段每一次循环都直接用DOM赋值
2. 第二段是先将内容缓存到局部变量中,最后使用一次DOM赋值。
测试结果以每秒钟执行测试代码的次数(Ops/sec
)显示,这个数值越大越好。
除了这个结果外,同时会显示测试过程中的统计误差,以及相对最好的慢了多少(%),统计误差也是非常重要的指标。
二、选择器API
有时候为了得到需要的元素列表,需要组合调用getElementById等并遍历返回的节点,但这种繁密的过程效率低下。
使用CSS选择器是一种定位节点的便利途径,querySelectorAll就是DOM的原生方法。
//DOM组合API
var elements = document.getElementById('menu').getElementsByTagName('a');
//替换为简便的CSS选择器
var elements = document.querySelectorAll('#menu a');
上面的例子不能体现效率的区别, 后面又改写了一个。在codepen中书写了一个例子,可以在线查看。
//从列表中选出CSS类是one的节点
var elements = document.querySelectorAll('#menu a.one'); var elements = document.getElementById('menu').getElementsByTagName('a'), list=[];
for(var i=0, len=elements.length; i<len; i++) {
if(elements[i].className == 'one') {
list.push(elements[i]);
}
}
三、重绘与重排
在《CSS动画与JavaScript动画》中层提到过页面渲染的一般过程为JavaScript > 计算样式 > 布局 > 绘制 > 渲染层合并。
Layout(重排)和Paint(重绘)是整个环节中最为耗时的两环,所以我们尽量避免着这两个环节。
当DOM的变化影响了元素的几何属性(宽和高)将会发生重排
(reflow);
完成重排后,浏览器会重新绘制受影响的部分到屏幕中,此过程为重绘
(repaint)。
1)重排何时发生
1. 添加或删除可见的DOM元素
2. 元素位置改变
3. 元素尺寸改变(包括外边距、内边距、边框宽度、宽、高等属性)
4. 内容改变,例如文本改变或图片被不同尺寸的替换掉。
5. 页面渲染器初始化。
6. 浏览器窗口尺寸改变。
2)批量执行重排
下面代码看上去会重排3次,但其实只会重排1次,大多数浏览器通过队列化修改和批量显示优化重排版过程。
//渲染树变化的排队和刷新
var ele = document.getElementById('myDiv');
ele.style.borderLeft = '1px';
ele.style.borderRight = '2px';
ele.style.padding = '5px';
但下列操作将会强迫队列刷新并要求所有计划改变的部分立刻应用:
offsetTop, offsetLeft, offsetWidth, offsetHeight
scrollTop, scrollLeft, scrollWidth, scrollHeight
clientTop, clientLeft, clientWidth, clientHeight
getComputedStyle() (currentStyle in IE)(在 IE 中此函数称为 currentStyle)
像offsetHeight属性需要返回最新的布局信息,因此浏览器不得不执行渲染队列中的“待处理变化”并触发重排以返回正确的值。
对于尺寸坐标相关的信息可以参考《JavaScript中尺寸、坐标》。
3)最小化重绘和重排
1. cssText和class
cssText可以一次设置多个CSS属性。class也可以一次性设置,并且更清晰,更易于维护,但有前提条件,就是不依赖于运行逻辑和计算的情况。
// cssText
ele.style.cssText = 'border-left: 1px; border-right: 2px; padding: 5px;';
// class
ele.className = 'active';
在《JavaScript特性(attribute)、属性(property)和样式(style)》详细介绍了CSS相关的JS操作。
2. 批量修改DOM
2.1 隐藏元素display:none
,应用修改,重新显示display:block
。
2.2 使用文档片段fragment
,在片段上操作节点,再拷贝回文档。
//文档片段(fragment)
var fragment = document.createDocumentFragment();
var li = document.createElement('li');
li.innerHTML = 'banana';
fragment.appendChild(li);
document.getElementById('fruit').appendChild(fragment);
2.3 将原始元素拷贝到一个脱离文档的节点中(例如position:absolute),修改副本,完成后再替换原始元素。
四、其它章节性能介绍
1)第一章 加载和执行
将<script>标签放到页面底部,也就是</body>闭合标签之前。
多种无阻塞下载JavaScript的方法:
1. 使用<script>标签的defer
属性。页面解析到<script>标签时开始下载,但并不会执行,直到DOM加载完(onload
事件触发前)。
2. 动态创建<script>元素来下载并执行代码。无论在何时启动下载,文件的下载和执行过程不会阻塞页面其它进程,但返回的代码通常会立刻执行。
3. 使用XHR对象下载JavaScript代码并注入页面中。优点是下载后不会自动执行,所有主流浏览器都支持,但不能跨域下载。
2)第二章 数据存取
1. 每遇到一个变量,就会经历一次标识符解析的过程,以决定在哪里获取和存储数据。在执行环境的作用域中,标识符所在的位置越深,读写速度也就越慢。因此函数中读写局部变量是最快的,读写全局变量是最慢的。
2. 由于对象成员可能包含其它成员,例如window.location.href
。每次遇到点操作符,嵌套成员会导致JavaScript引擎搜索全部对象成员。对象成员嵌套越深,读取速度越慢。location.href
就比window.location.href
快。
3)第五章 字符串与正则表达式
str = str + "one";//性能高
str = "one" + str;//性能差
1. 除IE外,浏览器会简单的将第二个字符串拷贝到第一个的后面,如果变量str很大的话,就会出现性能损耗(内存占用)就会很高。
2. 正则优化包括:减少分支数量,缩小分支范围;使用非捕获数组;只捕获感兴趣的文本以减少后期处理;使用合适的量词;化繁为简,分解复杂的正则;
4)第六章 快速响应的用户界面
使用定时器让出时间片段,分割大型任务,在文章《JavaScript定时器分析》中有具体分析。
5)第七章 Ajax
Mutipart XHR
允许客户端只用一个HTTP请求就可以从服务器向客户端传送多个资源。
将资源文件(CSS、HTML、JavaScript、Base64编码图片)打包成一个由双方约定的字符串分隔符,发送到客户端。
然后用JavaScript代码处理这个字符串,根据“mime-type”类型和传入的头信息解析每个资源。
6)第九章 构建并部署高性能JavaScript应用
1. 合并JavaScript文件以减少HTTP请求数。
2. 压缩JavaScript文件。
3. 在服务器端压缩JavaScript文件(Gzip编码)。
4. 正确设置HTTP响应头来缓存JavaScript文件,通过向文件名增加时间戳避免缓存问题。
5. 使用CDN(Content Delivery Network)提供JavaScript文件。
第八章 编程实践内容比较多,单独令出来作为一节。
五、第八章 编程实践
1)使用Object/Array直接量
代码例下:
var myObject = {
name: "pwstrick",
age: 29
};
var myArr = ["pwstrick", 29];
2)避免重复工作
也就是惰性模式。减少每次代码执行时的重复性分支判断,通过对对象重定义来屏蔽原对象中的分支判断。
惰性模式分为两种:第一种文件加载后立即执行对象方法来重定义,第二种是当第一次使用方法对象时来重定义。可参考在线demo代码。
在文章《JavaScript设计模式》中有更多的设计模式介绍。
3)位运算
1. 用位运算取代纯数学操作,比如对2取模digit%2
可以判断偶数与奇数。
2. 位掩码技术,使用单个数字的每一位来判断选项是否成立。掩码中每个选项的值都是2的幂。例如:
var OPTION_A = 1, OPTION_B = 2, OPTION_C = 4, OPTION_D = 8, OPTION_E = 16;
//用按位或运算创建一个数字来包含多个设置选项
var options = OPTION_A | OPTION_C | OPTION_D;
//接下来可以用按位与操作来判断给定的选项是否可用
//选项A是否在列表中
if(options & OPTION_A) {
//...
}
3. 用按位左移(<<)做乘法,用按位右移做除法(>>),例如digit*2
可以替换成digit<<2
。
4)原生方法
无论你的代码如何优化,都比不上JavaScript引擎提供的原生方法快。
1. 数学运算用内置的Math对象中提供的方法。
2. 用原生的CSS选择器查找DOM节点,querySelector或querySelectorAll。
参考资料:
JavaScript性能优化 DOM编程的更多相关文章
- JS性能优化——DOM编程
浏览器中的DOM 天生就慢 DOM是个与语言无关的API,它在浏览器中的接口却是用JavaScript实现的.客户端脚本编程大多数时候是在个底层文档打交道,DOM就成为现在JavaScript编码中 ...
- JavaScript性能优化
如今主流浏览器都在比拼JavaScript引擎的执行速度,但最终都会达到一个理论极限,即无限接近编译后程序执行速度. 这种情况下决定程序速度的另一个重要因素就是代码本身. 在这里我们会分门别类的介绍J ...
- JavaScript性能优化篇js优化
JavaScript性能优化篇js优化 随着Ajax越来越普遍,Ajax引用的规模越来越大,Javascript代码的性能越来越显得重要,我想这就是一个很典型的例子,上面那段代码因为会被频繁使用, ...
- javascript性能优化-repaint和reflow
repaint(重绘) ,repaint发生更改时,元素的外观被改变,且在没有改变布局的情况下发生,如改变outline,visibility,background color,不会影响到dom结构渲 ...
- 摘:JavaScript性能优化小知识总结
原文地址:http://www.codeceo.com/article/javascript-performance-tips.html JavaScript的性能问题不容小觑,这就需要我们开发人员在 ...
- Javascript 性能优化的一点技巧
把优秀的编程方式当成一种习惯,融入到日常的编程当中.下图是今天想到的一点Javascript 性能优化的技巧,分享一下,抛砖引玉.
- JavaScript性能优化小窍门汇总(含实例)
在众多语言中,JavaScript已经占有重要的一席之地,利用JavaScript我们可以做很多事情 , 应用广泛.在web应用项目中,需要大量JavaScript的代码,将来也会越来越多.但是由于J ...
- JavaScript性能优化小知识总结(转)
JavaScript的性能问题不容小觑,这就需要我们开发人员在编写JavaScript程序时多注意一些细节,本文非常详细的介绍了一下JavaScript性能优化方面的知识点,绝对是干货. 前言 一直在 ...
- Javascript性能优化阅读笔记
第一章 加载和执行 大多数浏览器都是用单一进程处理UI界面的刷新和JavaScript的脚本执行,所以同一时间只能做一件事,Javascript执行过程耗时越久,浏览器等待响应的时间就越长. 所以,H ...
随机推荐
- (一) 这就是所谓的Node.js------单线程,非阻塞,事件驱动
Node.js 第一天笔记(V1) 一:Node.js到底是从何而来 2008年的秋天,一个名叫做Ryan Dahl(罗伊・达尔)的年轻人在玩了几年服务器编程之后,越发感到服务器高并发性能的瓶颈是一个 ...
- 【转】flash air中读取本地文件的三种方法
actionscript中读取本地文件操作有两种代码如下 1.使用File和FileStream两个类,FileStream负责读取数据的所以操作:(同步操作) var stream:FileStre ...
- AngularJS1.X学习笔记1-整体看看
听说 明天是愚人节,这与我有什么关系呢!我可 不想被愚弄,但是但是,我这么笨怎么才能不被愚弄呢?左思右想,我决定从现在开始闭关,闭关干啥哩?学习!学习AngularJS.以前学习过Angular的,不 ...
- 修改Gradle 和Maven本地仓库的位置 方法
关于Maven的配置: 用过Maven的兄弟应该知道Maven可以通过配置 conf文件夹下面的settings.xml文件来修改maven下载的包,默认是下在c盘的用户文件夹下的.m2中,日积月累. ...
- node.js 中模块的循环调用问题详解
首先,我们看一下图示代码,每一个注释其实代表一个 js 文件.所以下面其实是三个 js 文件 .第一个是我们要运行的 main 文件,后面两个是 a, b 文件. 从上面可以看书 a ,b 两个模 ...
- C#网络程序设计(3)网络传输编程之TCP编程
网络传输编程指基于各种网络协议进行编程,包括TCP编程,UDP编程,P2P编程.本节介绍TCP编程. (1)TCP简介: TCP是TCP/IP体系中最重要的传输层协议,它提供全双工和可 ...
- 不完全CSS3图解
温故而知新.用XMind总结了下CSS3,打钩的代表比较常用的.希望对大家整体上理解CSS3有所帮助吧.
- 蓝桥杯-骰子游戏-java
/* (程序头部注释开始) * 程序的版权和版本声明部分 * Copyright (c) 2016, 广州科技贸易职业学院信息工程系学生 * All rights reserved. * 文件名称: ...
- codeforces 591B Rebranding (模拟)
Rebranding Problem Description The name of one small but proud corporation consists of n lowercase E ...
- Yeelink初步体验
环境 Qemu: 2.8.0 开发板:vexpress-ca9 概述 前面的博文已经使我们的虚拟开发板具备了访问外网的目的,离物联网越来越近了.要玩物联网,Yeelink不得不说,它提供了 ...