使用DocumentFragment优化多次append
添加多个dom元素时,先将元素append到DocumentFragment中,最后统一将DocumentFragment添加到页面。该做法可以减少页面渲染dom元素的次数。经IE和FX下测试,在append1000个元素时,效率能提高10%-30%,FX下提升较为明显。
前:
1 |
for ( var i = 0; i < 1000; i++) { |
2 |
var el = document.createElement( 'p' ); |
4 |
document.body.appendChild(el); |
后:
1 |
var frag = document.createDocumentFragment(); |
2 |
for ( var i = 0; i < 1000; i++) { |
3 |
var el = document.createElement( 'p' ); |
7 |
document.body.appendChild(frag); |
通过模板元素clone,替代createElement
通过一个模板dom对象cloneNode,效率比直接创建element高。性能提高不明显,约为10%左右。在低于100个元素create和append操作时,没有优势。
1 |
var frag = document.createDocumentFragment(); |
2 |
for ( var i = 0; i < 1000; i++) { |
3 |
var el = document.createElement( 'p' ); |
7 |
document.body.appendChild(frag); |
1 |
var frag = document.createDocumentFragment(); |
2 |
var pEl = document.getElementsByTagName( 'p' )[0]; |
3 |
for ( var i = 0; i < 1000; i++) { |
4 |
var el = pEl.cloneNode( false ); |
8 |
document.body.appendChild(frag); |
使用一次innerHTML赋值代替构建dom元素
根据数据构建列表样式的时候,使用设置列表容器innerHTML的方式,比构建dom元素并append到页面中的方式,效率有数量级上的提高。
1 |
var frag = document.createDocumentFragment(); |
2 |
for ( var i = 0; i < 1000; i++) { |
3 |
var el = document.createElement( 'p' ); |
7 |
document.body.appendChild(frag); |
2 |
for ( var i = 0; i < 1000; i++) { |
3 |
html.push( '<p>' + i + '</p>' ); |
5 |
document.body.innerHTML = html.join( '' ); |
使用firstChild和nextSibling代替childNodes遍历dom元素
约能获得30%-50%的性能提高。逆向遍历时使用lastChild和previousSibling。
1 |
var nodes = element.childNodes; |
2 |
for ( var i = 0, l = nodes.length; i < l; i++) { |
1 |
var node = element.firstChild; |
4 |
node = node.nextSibling; |
使用Array做为StringBuffer,代替字符串拼接的操作
IE在对字符串拼接的时候,会创建临时的String对象;经测试,在IE下,当拼接的字符串越来越大时,运行效率会急剧下降。Fx和Opera都对字符串拼接操作进行了优化;经测试,在Fx下,使用Array的join方式执行时间约为直接字符串拼接的1.4倍。
3 |
for ( var i = 0; i < 10000; i++) { |
4 |
str += '123456789123456789' ; |
6 |
alert( new Date() - now); |
3 |
for ( var i = 0; i < 10000; i++) { |
4 |
strBuffer.push( '123456789123456789' ); |
6 |
var str = strBuffer.join( '' ); |
7 |
alert( new Date() - now); |
将循环控制量保存到局部变量
对数组和列表对象的遍历时,提前将length保存到局部变量中,避免在循环的每一步重复取值。
1 |
var list = document.getElementsByTagName( 'p' ); |
2 |
for ( var i = 0; i < list.length; i++) { |
1 |
var list = document.getElementsByTagName( 'p' ); |
2 |
for ( var i = 0, l = list.length; i < l; i++) { |
顺序无关的遍历时,用while替代for
该方法可以减少局部变量的使用。比起效率优化,更能直接看到的是字符数量的优化。该做法有程序员强迫症的嫌疑。
1 |
var arr = [1,2,3,4,5,6,7]; |
3 |
for ( var i = 0, l = arr.length; i < l; i++) { |
1 |
var arr = [1,2,3,4,5,6,7]; |
2 |
var sum = 0, l = arr.length; |
使用三目运算符替代条件分支
需要不断执行的时候,优先考虑使用setInterval
setTimeout每一次都会初始化一个定时器。setInterval只会在开始的时候初始化一个定时器。
4 |
if (timeoutTimes < 10) { |
5 |
setTimeout(timeout, 10); |
4 |
if (intervalTimes >= 10) { |
8 |
var interv = setInterval(interval, 10); |
使用function而不是string
如果把字符串作为setTimeout和setInterval的参数,浏览器会先用这个字符串构建一个function。
2 |
setTimeout( 'num++' , 10); |
5 |
setTimeout(addNum, 10); |
重复使用的调用结果,事先保存到局部变量
避免多次取值的调用开销。
1 |
var h1 = element1.clientHeight + num1; |
2 |
var h2 = element1.clientHeight + num2; |
1 |
var eleHeight = element1.clientHeight; |
2 |
var h1 = eleHeight + num1; |
3 |
var h2 = eleHeight + num2; |
使用直接量
1 |
var a = new Array(param,param,...) -> var a = [] |
2 |
var foo = new Object() -> var foo = {} |
3 |
var reg = new RegExp() -> var reg = /.../ |
避免使用with
with虽然可以缩短代码量,但是会在运行时构造一个新的scope。OperaDev上还有这样的解释,使用with语句会使得解释器无法在语法解析阶段对代码进行优化。对此说法,无法验证。
巧用||和&&布尔运算符
1 |
function eventHandler (e) { |
2 |
if (!e) e = window.event; |
1 |
function eventHandler (e) { |
还有下面的例子:
1 |
myobj && doSomething(myobj); |
类型转换
数字转换成字符串,应用"" + 1,性能上:("" +) > String() > .toString() > new String();
浮点数转换成整型,不使用parseInt(), parseInt()是用于将字符串转换成数字,而不是浮点数和整型之间的转换,建议使用Math.floor()或者Math.round()。
对于自定义的对象,推荐显式调用toString()。内部操作在尝试所有可能性之后,会尝试对象的toString()方法尝试能否转化为String。
循环引用
如果循环引用中包含DOM对象或者ActiveX对象,那么就会发生内存泄露。内存泄露的后果是在浏览器关闭前,即使是刷新页面,这部分内存不会被浏览器释放。
简单的循环引用:
1 |
var el = document.getElementById( 'MyElement' ); |
2 |
var func = function () {…} |
但是通常不会出现这种情况。通常循环引用发生在为dom元素添加闭包作为expendo的时候。
2 |
var el = document.getElementById( 'MyElement' ); |
3 |
el.onclick = function () {……} |
init在执行的时候,当前上下文我们叫做context。这个时候,context引用了el,el引用了function,function引用了context。这时候形成了一个循环引用。
置空dom对象
2 |
var el = document.getElementById( 'MyElement' ); |
3 |
el.onclick = function () {……} |
2 |
var el = document.getElementById( 'MyElement' ); |
3 |
el.onclick = function () {……} |
将el置空,context中不包含对dom对象的引用,从而打断循环应用。如果我们需要将dom对象返回,可以用如下方法:
2 |
var el = document.getElementById( 'MyElement' ); |
3 |
el.onclick = function () {……} |
02 |
var el = document.getElementById( 'MyElement' ); |
03 |
el.onclick = function () {……} |
构造新的context:
2 |
var el = document.getElementById( 'MyElement' ); |
3 |
el.onclick = function () {……} |
1 |
function elClickHandler() {……} |
3 |
var el = document.getElementById( 'MyElement' ); |
4 |
el.onclick = elClickHandler; |
把function抽到新的context中,这样,function的context就不包含对el的引用,从而打断循环引用。
通过javascript创建的dom对象,必须append到页面中
IE下,脚本创建的dom对象,如果没有append到页面中,刷新页面,这部分内存是不会回收的!
02 |
var gc = document.getElementById( 'GC' ); |
03 |
for ( var i = 0; i < 5000 ; i++) |
05 |
var el = document.createElement( 'div' ); |
06 |
el.innerHTML = "test" ; |
07 |
//下面这句可以注释掉,看看浏览器在任务管理器中,点击按钮然后刷新后的内存变化 |
释放dom元素占用的内存
将dom元素的innerHTML设置为空字符串,可以释放其子元素占用的内存。
在rich应用中,用户也许会在一个页面上停留很长时间,可以使用该方法释放积累得越来越多的dom元素使用的内存。
释放javascript对象
在rich应用中,随着实例化对象数量的增加,内存消耗会越来越大。所以应当及时释放对对象的引用,让GC能够回收这些内存控件。
对象:obj = null,对象属性:delete obj.myproperty。
数组item:使用数组的splice方法释放数组中不用的item。
避免string的隐式装箱
对string的方法调用,比如'xxx'.length,浏览器会进行一个隐式的装箱操作,将字符串先转换成一个String对象。推荐对声明有可能使用String实例方法的字符串时,采用如下写法:
var myString = new String('Hello World');
- 编程技巧│提高 Javascript 代码效率的技巧
目录 一.变量声明 二.三元运算符 三.解构赋值 四.解构交换 五.箭头函数 六.字符串模版 七.多值匹配 八.ES6对象简写 九.字符串转数字 十.次方相乘 十一.数组合并 十二.查找数组最大值最小 ...
- javascript高级教程:如何优化javascript代码性能
在web前端开发中,为实现一些动态效果,减小页面大小,我们一般都会使用JavaScript技术来进行相关设置.但是初学者在编写JavaScript代码的时候,往往都是比较低质的代码,那如何才能提高Ja ...
- 高效率JavaScript编写技巧
最近在编写一个JavaScript框架,发现有很多细节注意得不够,担心长时间积累会导致框架实际应用的时候出现严重的效率问题.于是开始关注JavaScript提高效率的一些技巧,在这里分享给大家. 1. ...
- 编写JavaScript 代码的5个小技巧
1.Array.includes 与条件判断 一般我们判断或用 || // condition function test(fruit) { if (fruit == "apple" ...
- 新书《编写可测试的JavaScript代码 》出版,感谢支持
本书介绍 JavaScript专业开发人员必须具备的一个技能是能够编写可测试的代码.不管是创建新应用程序,还是重写遗留代码,本书都将向你展示如何为客户端和服务器编写和维护可测试的JavaScript代 ...
- 使用 Promises 编写更优雅的 JavaScript 代码
你可能已经无意中听说过 Promises,很多人都在讨论它,使用它,但你不知道为什么它们如此特别.难道你不能使用回调么?有什么了特别的?在本文中,我们一起来看看 Promises 是什么以及如何使用它 ...
- 编写快速、高效的JavaScript代码
许多Javascript引擎都是为了快速运行大型的JavaScript程序而特别设 计的,例如Google的V8引擎(Chrome浏览器,Node均使用该引擎).在开发过程中,如果你关心你程序的内存和 ...
- 编写高质量JavaScript代码的68个有效方法
简介: <Effective JavaScript:编写高质量JavaScript代码的68个有效方法>共分为7章,分别涵盖JavaScript的不同主题.第1章主要讲述最基本的主题,如版 ...
- 14条最佳JS代码编写技巧
http://gaohaixian.blog.163.com/blog/static/123260105201142645458315/写任何编程代码,不同的开发者都会有不同的见解.但参考一下总是好的 ...
随机推荐
- lintcode514 栅栏染色
栅栏染色 我们有一个栅栏,它有n个柱子,现在要给柱子染色,有k种颜色可以染.必须保证不存在超过2个相邻的柱子颜色相同,求有多少种染色方案. 注意事项 n和k都是非负整数 您在真实的面试中是否遇到过这个 ...
- JAVA 面试须知
本篇文章会对面试中常遇到的Java技术点进行全面深入的总结,帮助我们在面试中更加得心应手,不参加面试的同学也能够借此机会梳理一下自己的知识体系,进行查漏补缺. 1. Java中的原始数据类型都有哪些, ...
- 【转】cocos2d工具汇总
位图字体工具Bitmap Font Tools BMFont (Windows)FonteditorGlyph DesignerHieroLabelAtlasCreator 粒子编辑工具Particl ...
- 数据库Mysql的学习(六)-子查询和多表操作
)*0.05 WHERE card_id ='20121xxxxxx'; //子查询就是一个嵌套先计算子查询 SELECT * FROM borrow WHERE book_id =(SELECT b ...
- ElasticSearch 论坛搜索查询语句
概述 研究论坛搜索如何综合时间和TF/IDF权重. 自定义权重计算的效率问题 数据结构 假设有一个论坛的搜索 字段包括: subject:标题 message:内容 dateline:发布时间 tag ...
- Mybatis ResultMap(2)
SQL 映射XML 文件是所有sql语句放置的地方.需要定义一个workspace,一般定义为对应的接口类的路径.写好SQL语句映射文件后,需要在MyBAtis配置文件mappers标签中引用,例如: ...
- 自测之Lesson13:共享内存
题目:创建一个64K的共享内存. 实现代码: #include <stdio.h> #include <sys/ipc.h> #include <sys/shm.h> ...
- c# 四则运算出错
不同类型值之间不可直接相减,long和short得出的差继续参与运算出错. 有待深究.
- 由作业题引发对C++引用的一些思考
首先分析一段代码: #include <bits/c++config.h> #include <ostream> #include <iostream> #incl ...
- Linux 路由 学习笔记 之一 相关的数据结构
http://blog.csdn.net/lickylin/article/details/38326719 从现在开始学习路由相关的代码,在分析代码之前, 我们还是先分析数据结构,把数据结构之间的关 ...