[转载]编写高性能js
一.执行效率
1. DOM
1.1 使用DocumentFragment优化多次append
说明:添加多个dom元素时,先将元素append到DocumentFragment中,最后统一将DocumentFragment添加到页面。
该做法可以减少页面渲染dom元素的次数。经IE和Fx下测试,在append1000个元素时,效率能提高10%-30%,Fx下提升较为明显。 服用前:
for (var i = 0; i < 1000; i++) {
var el = document.createElement(‘p’);
el.innerHTML = i;
document.body.appendChild(el);
} 服用后:
var frag = document.createDocumentFragment();
for (var i = 0; i < 1000; i++) {
var el = document.createElement(‘p’);
el.innerHTML = i;
frag.appendChild(el);
}
document.body.appendChild(frag); 1.2 通过模板元素clone,替代createElement
说明:通过一个模板dom对象cloneNode,效率比直接创建element高。
性能提高不明显,约为10%左右。在低于100个元素create和append操作时,没有优势。 服用前:
var frag = document.createDocumentFragment();
for (var i = 0; i < 1000; i++) {
var el = document.createElement(‘p’);
el.innerHTML = i;
frag.appendChild(el);
}
document.body.appendChild(frag); 服用后:
var frag = document.createDocumentFragment();
var pEl = document.getElementsByTagName(‘p’)[0];
for (var i = 0; i < 1000; i++) {
var el = pEl.cloneNode(false);
el.innerHTML = i;
frag.appendChild(el);
}
document.body.appendChild(frag); 1.3 使用一次innerHTML赋值代替构建dom元素
说明:根据数据构建列表样式的时候,使用设置列表容器innerHTML的方式,比构建dom元素并append到页面中的方式,效率有数量级上的提高。 服用前:
var frag = document.createDocumentFragment();
for (var i = 0; i < 1000; i++) {
var el = document.createElement(‘p’);
el.innerHTML = i;
frag.appendChild(el);
}
document.body.appendChild(frag); 服用后:
var html = [];
for (var i = 0; i < 1000; i++) {
html.push(‘<p>’ + i + ‘</p>’);
}
document.body.innerHTML = html.join(”); 1.4 使用firstChild和nextSibling代替childNodes遍历dom元素
说明:约能获得30%-50%的性能提高。逆向遍历时使用lastChild和previousSibling。 服用前:
var nodes = element.childNodes;
for (var i = 0, l = nodes.length; i < l; i++) {
var node = nodes[i];
……
} 服用后:
var node = element.firstChild;
while (node) {
……
node = node.nextSibling;
} 2. 字符串 2.1 使用Array做为StringBuffer,代替字符串拼接的操作
说明:IE在对字符串拼接的时候,会创建临时的String对象;经测试,在IE下,当拼接的字符串越来越大时,运行效率会急剧下降。Fx和Opera都对字符串拼接操作进行了优化;经测试,在Fx下,使用Array的join方式执行时间约为直接字符串拼接的1.4倍。 服用前:
var now = new Date();
var str = ”;
for (var i = 0; i < 10000; i++) {
str += ’123456789123456789′;
}
alert(new Date() – now); 服用后:
var now = new Date();
var strBuffer = [];
for (var i = 0; i < 10000; i++) {
strBuffer.push(’123456789123456789′);
}
var str = strBuffer.join(”);
alert(new Date() – now); 3. 循环语句 3.1 将循环控制量保存到局部变量
说明:对数组和列表对象的遍历时,提前将length保存到局部变量中,避免在循环的每一步重复取值。 服用前:
var list = document.getElementsByTagName(‘p’);
for (var i = 0; i < list.length; i++) {
……
} 服用后:
var list = document.getElementsByTagName(‘p’);
for (var i = 0, l = list.length; i < l; i++) {
……
} 3.2 顺序无关的遍历时,用while替代for
说明:该方法可以减少局部变量的使用。比起效率优化,更能直接看到的是字符数量的优化。该做法有程序员强迫症的嫌疑。 服用前:
var arr = [1,2,3,4,5,6,7];
var sum = 0;
for (var i = 0, l = arr.length; i < l; i++) {
sum += arr[i];
} 服用后:
var arr = [1,2,3,4,5,6,7];
var sum = 0, l = arr.length;
while (l–) {
sum += arr[l];
} 4. 条件分支 4.1 将条件分支,按可能性顺序从高到低排列
说明:可以减少解释器对条件的探测次数。 4.2 在同一条件子的多(>2)条件分支时,使用switch优于if
说明:switch分支选择的效率高于if,在IE下尤为明显。4分支的测试,IE下switch的执行时间约为if的一半。 4.3 使用三目运算符替代条件分支
服用前:
if (a > b) {
num = a;
} else {
num = b;
} 服用后:
num = a > b ? a : b; 5. 定时器 5.1 需要不断执行的时候,优先考虑使用setInterval
说明:setTimeout每一次都会初始化一个定时器。setInterval只会在开始的时候初始化一个定时器 服用前:
var timeoutTimes = 0;
function timeout () {
timeoutTimes++;
if (timeoutTimes < 10) {
setTimeout(timeout, 10);
}
}
timeout(); 服用后:
var intervalTimes = 0;
function interval () {
intervalTimes++;
if (intervalTimes >= 10) {
clearInterval(interv);
}
}
var interv = setInterval(interval, 10); 5.2 使用function而不是string
说明:如果把字符串作为setTimeout和setInterval的参数,浏览器会先用这个字符串构建一个function。 服用前:
var num = 0;
setTimeout(‘num++’, 10); 服用后:
var num = 0;
function addNum () {
num++;
}
setTimeout(addNum, 10); 6. 其他 6.1 尽量不使用动态语法元素
说明:eval、Function、execScript等语句会再次使用javascript解析引擎进行解析,需要消耗大量的执行时间。 6.2 重复使用的调用结果,事先保存到局部变量
说明:避免多次取值的调用开销。 服用前:
var h1 = element1.clientHeight + num1;
var h2 = element1.clientHeight + num2; 服用后:
var eleHeight = element1.clientHeight;
var h1 = eleHeight + num1;
var h2 = eleHeight + num2; 6.3 使用直接量
说明:
var a = new Array(param,param,…) -> var a = []
var foo = new Object() -> var foo = {}
var reg = new RegExp() -> var reg = /…/ 6.4 避免使用with
说明: with虽然可以缩短代码量,但是会在运行时构造一个新的scope。
OperaDev上还有这样的解释,使用with语句会使得解释器无法在语法解析阶段对代码进行优化。对此说法,无法验证。 服用前:
with (a.b.c.d) {
property1 = 1;
property2 = 2;
} 服用后:
var obj = a.b.c.d;
obj.property1 = 1;
obj.property2 = 2; 6.5 巧用||和&&布尔运算符
重要程度:★★★ 服用前:
function eventHandler (e) {
if(!e) e = window.event;
} 服用后:
function eventHandler (e) {
e = e || window.event;
} 服用前:
if (myobj) {
doSomething(myobj);
} 服用后:
myobj && doSomething(myobj); 6.6 类型转换
说明:
1). 数字转换成字符串,应用”" + 1,性能上:(“” +) > String() > .toString() > new String();
2). 浮点数转换成整型,不使用parseInt(), parseInt()是用于将字符串转换成数字,而不是浮点数和整型之间的转换,建议使用Math.floor()或者Math.round()
3). 对于自定义的对象,推荐显式调用toString()。内部操作在尝试所有可能性之后,会尝试对象的toString()方法尝试能否转化为String。 二.内存管理 2.1 循环引用
说明:如果循环引用中包含DOM对象或者ActiveX对象,那么就会发生内存泄露。内存泄露的后果是在浏览器关闭前,即使是刷新页面,这部分内存不会被浏览器释放。
简单的循环引用:
var el = document.getElementById(‘MyElement’);
var func = function () {…}
el.func = func;
func.element = el; 但是通常不会出现这种情况。通常循环引用发生在为dom元素添加闭包作为expendo的时候。 如:
function init() {
var el = document.getElementById(‘MyElement’);
el.onclick = function () {……}
}
init(); init在执行的时候,当前上下文我们叫做context。这个时候,context引用了el,el引用了function,function引用了context。这时候形成了一个循环引用。 下面2种方法可以解决循环引用: 1) 置空dom对象 服用前:
function init() {
var el = document.getElementById(‘MyElement’);
el.onclick = function () {……}
}
init(); 服用后:
function init() {
var el = document.getElementById(‘MyElement’);
el.onclick = function () {……}
el = null;
}
init(); 将el置空,context中不包含对dom对象的引用,从而打断循环应用。
如果我们需要将dom对象返回,可以用如下方法: 服用前:
function init() {
var el = document.getElementById(‘MyElement’);
el.onclick = function () {……}
return el;
}
init(); 服用后:
function init() {
var el = document.getElementById(‘MyElement’);
el.onclick = function () {……}
try{
return el;
} finally {
el = null;
}
}
init(); 2) 构造新的context
服用前:
function init() {
var el = document.getElementById(‘MyElement’);
el.onclick = function () {……}
}
init(); 服用后:
function elClickHandler() {……}
function init() {
var el = document.getElementById(‘MyElement’);
el.onclick = elClickHandler;
}
init(); 把function抽到新的context中,这样,function的context就不包含对el的引用,从而打断循环引用。 2.2 通过javascript创建的dom对象,必须append到页面中
说明:IE下,脚本创建的dom对象,如果没有append到页面中,刷新页面,这部分内存是不会回收的! 示例代码: function create () {
var gc = document.getElementById(‘GC’);
for (var i = 0; i < 5000 ; i++)
{
var el = document.createE
lement(‘div’);
el.innerHTML = “test”; //下面这句可以注释掉,看看浏览器在任务管理器中,点击按钮然后刷新后的内存变化
gc.appendChild(el);
}
} 2.3 释放dom元素占用的内存
说明:
将dom元素的innerHTML设置为空字符串,可以释放其子元素占用的内存。
在rich应用中,用户也许会在一个页面上停留很长时间,可以使用该方法释放积累得越来越多的dom元素使用的内存。 2.4 释放javascript对象
说明:在rich应用中,随着实例化对象数量的增加,内存消耗会越来越大。所以应当及时释放对对象的引用,让GC能够回收这些内存控件。
对象:obj = null
对象属性:delete obj.myproperty
数组item:使用数组的splice方法释放数组中不用的item 2.5 避免string的隐式装箱
说明:对string的方法调用,比如’xxx’.length,浏览器会进行一个隐式的装箱操作,将字符串先转换成一个String对象。推荐对声明有可能使用String实例方法的字符串时,采用如下写法:
var myString = new String(‘Hello World’);
[转载]编写高性能js的更多相关文章
- 【JavaScript】【译】编写高性能JavaScript
英文链接:Writing Fast, Memory-Efficient JavaScript 很多JavaScript引擎,如Google的V8引擎(被Chrome和Node所用),是专门为需要快速执 ...
- 编写高性能JavaScript【转】
英文链接:Writing Fast, Memory-Efficient JavaScript 很多JavaScript引擎,如Google的V8引擎(被Chrome和Node所用),是专门为需要快速执 ...
- 编写高性能Javascript代码的若干建议
多年来,Javascript一直在web应用开发中占据重要的地位,但是很多开发者往往忽视一些性能方面的知识,特别是随着计算机硬件的不断升级,开发者越发觉得Javascript性能优化的好不好对网页的执 ...
- 编写高性能Web应用程序的10个技巧
这篇文章讨论了: ·一般ASP.NET性能的秘密 ·能提高ASP.NET表现的有用的技巧和窍门 ·在ASP.NET中使用数据库的建议 ·ASP.NET中的缓存和后台处理 使用ASP.NET编写一个We ...
- 编写高性能 Web 应用程序的 10 个技巧
使用 ASP.NET 编写 Web 应用程序的简单程度令人不敢相信.正因为如此简单,所以很多开发人员就不会花时间来设计其应用程序的结构,以获得更好的性能了.在本文中,我将讲述 10 个用于编写高性能 ...
- 转自微软内部资料:编写高性能 Web 应用程序的 10 个技巧
编写高性能 Web 应用程序的 10 个技巧 转自微软资料数据层性能技巧 1 — 返回多个结果集技巧 2 — 分页的数据访问技巧 3 — 连接池技巧 4 — ASP.NET 缓存 API技巧 5 — ...
- 编写高性能Javascript
编写高性能Javascript 多年来,Javascript一直在web应用开发中占据重要的地位,但是很多开发者往往忽视一些性能方面的知识,特别是随着计算机硬件的不断升级,开发者越发觉得Javascr ...
- [转]编写高性能的Lua代码
昨天晚上闲来无事,看室友在电脑上挂机玩游戏,用的一个辅助脚本,以为是lua写的脚本在跑,实际调查发现是按键精灵的脚本. 于是在网上找相关Lua开发游戏脚本的案例,看到一个人的博客,内容很不错,学到了很 ...
- 编写Node.js原生扩展
Node.js是一个强大的平台,理想状态下一切都都可以用javascript写成.然而,你可能还会用到许多遗留的库和系统,这样的话使用c++编写Node.JS扩展会是一个不错的注意. 以下所有例子的源 ...
随机推荐
- python开发_pickle
pickle模块使用的数据格式是python专用的,并且不同版本不向后兼容,同时也不能被其他语言说识别.要和其他语言交互,可以使用内置的json包使用pickle模块你可以把Python对象直接保存到 ...
- BZOJ 2818: Gcd 筛法
2818: Gcd 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=2818 Description 给定整数N,求1<=x,y< ...
- April Fools Day Contest 2016 C. Without Text 信号与系统
C. Without Text 题目连接: http://www.codeforces.com/contest/656/problem/C Description You can preview th ...
- leetcode76. Minimum Window Substring
leetcode76. Minimum Window Substring 题意: 给定字符串S和字符串T,找到S中的最小窗口,其中将包含复杂度O(n)中T中的所有字符. 例如, S ="AD ...
- SUSE Linux忘记root密码的对策
1)开机,进入GRUB界面: 此时有两个选择: SUSE LINUX ENTERPISE SERVER 10 SUSE LINUX ENTERPISE SERVER 10 (Failsafe) 移动光 ...
- 从网络得到数据--Arduino+以太网
昨天我们讨论了如何使用Arduino以太网插板建立服务器,并通过网络控制Arduino的引脚.今天我们来看看用插板做为客户端来从一个网页上得到信息并返回报告.我几个月前用的这个方法,当时我做了一个Ni ...
- High-current supply uses standard three-terminal regulator
Voltage-regulator design for high output currents can be a critical and difficult task. Although vol ...
- Percona-Toolkit学习之安装和配置
http://blog.chinaunix.net/uid-26446098-id-3390779.html
- CentOS,Fedora,Debian,Ubuntu,SuSE——我到底爱谁
主观情绪上,一直都不是特别喜欢RedHat,虽然它是毋庸置疑的老大,其实我并不介意有人说我肤浅,说这话的理由简单,redhat.com发布RedHat 9(简写为RH9)后,不再开发RedHat 10 ...
- Django 版本对应的 Python 版本
Django 版本对应的 Python 版本: Django 版本 Python 版本 1.8 2.7, 3.2 , 3.3, 3.4, 3.5 1.9, 1.10 2.7, 3.4, 3.5 1.1 ...