编写高效的JavaScript【well】
2012-02-17 14:41
267 查看
这两天在读《高性能网站建设进阶指南:Web开发者性能优化最佳实践》
第七章讲的是JavaScript的优化
关于JavaScript的代码优化之前还没看见过,感觉不错,跟大家一起分享下~
1.作用域
执行JavaScript代码时,JavaScript引擎会创建一个全局的执行上下文,而执行每一个函数时,也会创建一个对应的执行上下文,最终建立一个执行上下文的堆栈。每一个执行上下文对应一个作用域链,用于解析标识符。JavaScript在作用域链中查找标识符。标识符在作用域链中的位置越深,查找和访问它所需的时间也就越长。(只有基于V8 JavaScript引擎的Google chrome和基于Nitro JavaScript引擎的Safari4+例外,它们的存取速度之快,使标识符深度的影响微乎其微了)标识符在作用域链的位置越靠上,存取速度就越快。
局部变量是目前为止JavaScript中读写速度最快的标识符。因为它们存在于执行函数的活动对象中,解析标识符只需查找作用域链中的单个对象。请尽可能的使用局部变量。任何非局部变量在函数中的使用超过一次时,都应该将其存储为局部变量。
例如:
这个函数调用了两次document全局变量,为了更快的引用,应该把它存储到一个局部变量中。
全局变量对象始终是作用域链中最后一个对象,所以对全局标识符的解析总是最耗时的!
另外,存取数组中的某个值时,需要通过索引来查询数据存储的位置,而存取对象中的某个值时,需要通过属性值来查询数据存储的的位置。所以,请将函数中使用超过一次的对象属性或数组元素也存储为局部变量。
再另外一下,在代码执行过程中,作用域链通常是保持不变的,但是with语句和try-catch语句中的catch从句会临时增长执行上下文的作用域链。
2.流控制
条件判断优化:
在if语句中,随着条件总数的增加,条件越深,性能损失也越大。
可以将条件按频率降序排列。出现频率较高的条件放在前几位。
优化语句条件,可以借鉴二分查找算法的精髓
如果条件均为离散值,而非区间范围,则改写为switch语句
但是,并不是在条件均为离散值的情况下,switch语句的性能都由于if语句。在JavaScript中,当仅判断一到两个条件是,if语句通常比switch语句更快
优化条件判断还有另一个办法,数组查询(假设要判断的值value取值范围为1-10):
简单的用数组索引映射value变量,虽然查询数组的耗时也会随着进入数组的深度而增加,但是和每个条件都用if语句或switch语句来判断相比,增加的时间还是要小的很多。
循环优化:
简单提升循环性能:
for-in循环比其他循环慢,请在处理需要遍历的对象属性集或JSON对象的未知属性集时才采用它
进一步优化循环–展开循环:
使一次循环完成多次循环的工作
3.字符串优化
字符串连接:
字符串连接一直是JavaScript中性能最低的操作之一。
通常情况下的加法运算:
这意味着要创建中间字符串来存储连接的结果,频繁地在后台创建和销毁字符串会导致字符串连接的性能异常底下。
开发者利用了JavaScript的Array数组来补救:
不过,如今浏览器对字符串的优化已经改变了字符串连接的局面。IE8+、ff、safari、chrome、opera已经对加法运算做了优化使其比数组运算法更加快速。当字符串相对较小(少于20个字符)且连接的数量也较少时(少于1000个),所有浏览器使用加法运算符都能在不到1毫秒之内轻松完成连接。但增加连接字符串的数量或大小时,在IE7中性能会明显下降。在FF下,当字符串大小增加时,加法运算符和数组技术的性能差异会变小。在Safari下,当字符串连接数量增加时,这两种技术的性能差异也会同样变小。只有在chrome和opera下,加法运算符一直保持着显著的性能优势。所以,需要基于用户的浏览器来权衡使用哪种技术。当然,大多数情况下,加法运算符是首选。
裁剪字符串:
JavaScript没有用于移除字符串头尾空白的原生修剪方法。
用于弥补的函数:
但是,这个函数可以在正则表达式上优化性能。
对性能的影响来自于正则表达式的两个方面:一个方面是指明有两个匹配模式的管道运算符,另一方面是指明全局应用该模式的g标记。保持正则表达式尽可能的简单,可以提高性能。
Steven Levithan提出的在JavaScript中执行速度最快的裁剪字符串方式:
4.避免运行时间过长的脚本
JavaScript是单线程语言。所以在代码执行时会导致页面被冻结而出现假死。在一个时间段中,每个窗口或标签页都只能执行一个脚本,同时,所有用户的交互被中断。如果JavaScript代码未经过细心的设计,有可能长时间的冻结页面,而导致浏览器停止响应。最常见的脚本执行时间过长的原因包括:过多的DOM交互、过多的循环、过多的递归。
在复杂的WEB应用程序中,为了避免长时间的页面冻结而导致不能进行交互,需要人为地插入中断。
解决方案:使用定时器挂起。
实际上就是把某些代码排到JavaScript引擎队列中稍后执行,而页面可以利用这段引擎挂起的时间来进行交互。同样也可将定时器应用于大型数组处理中
最后,推荐下这本书:
第七章讲的是JavaScript的优化
关于JavaScript的代码优化之前还没看见过,感觉不错,跟大家一起分享下~
1.作用域
执行JavaScript代码时,JavaScript引擎会创建一个全局的执行上下文,而执行每一个函数时,也会创建一个对应的执行上下文,最终建立一个执行上下文的堆栈。每一个执行上下文对应一个作用域链,用于解析标识符。JavaScript在作用域链中查找标识符。标识符在作用域链中的位置越深,查找和访问它所需的时间也就越长。(只有基于V8 JavaScript引擎的Google chrome和基于Nitro JavaScript引擎的Safari4+例外,它们的存取速度之快,使标识符深度的影响微乎其微了)标识符在作用域链的位置越靠上,存取速度就越快。
局部变量是目前为止JavaScript中读写速度最快的标识符。因为它们存在于执行函数的活动对象中,解析标识符只需查找作用域链中的单个对象。请尽可能的使用局部变量。任何非局部变量在函数中的使用超过一次时,都应该将其存储为局部变量。
例如:
function createChildFor(elementId){ var element=document.getElementById(elementId), newElement=document.createElement('div'); element.appendChild(newElement); }
这个函数调用了两次document全局变量,为了更快的引用,应该把它存储到一个局部变量中。
全局变量对象始终是作用域链中最后一个对象,所以对全局标识符的解析总是最耗时的!
另外,存取数组中的某个值时,需要通过索引来查询数据存储的位置,而存取对象中的某个值时,需要通过属性值来查询数据存储的的位置。所以,请将函数中使用超过一次的对象属性或数组元素也存储为局部变量。
再另外一下,在代码执行过程中,作用域链通常是保持不变的,但是with语句和try-catch语句中的catch从句会临时增长执行上下文的作用域链。
2.流控制
条件判断优化:
在if语句中,随着条件总数的增加,条件越深,性能损失也越大。
可以将条件按频率降序排列。出现频率较高的条件放在前几位。
优化语句条件,可以借鉴二分查找算法的精髓
如果条件均为离散值,而非区间范围,则改写为switch语句
但是,并不是在条件均为离散值的情况下,switch语句的性能都由于if语句。在JavaScript中,当仅判断一到两个条件是,if语句通常比switch语句更快
优化条件判断还有另一个办法,数组查询(假设要判断的值value取值范围为1-10):
var results=[result0,result1,result2,result3,result3,result4,result5,result6,result7,result8,result9,result10]; return results[value];
简单的用数组索引映射value变量,虽然查询数组的耗时也会随着进入数组的深度而增加,但是和每个条件都用if语句或switch语句来判断相比,增加的时间还是要小的很多。
循环优化:
简单提升循环性能:
var values=[1,2,3,4,5]; for(var i=0;i<values.length;i++){//反复的比较计数变量和数组长度,这样做效率很低 values[i]++; } var length=values.length;//使用局部变量 for(var i=0;i<length;i++){//加快循环效率 values[i]++; } for(var i=length;i--;){ values[i]++; }//结束条件被改造为与0比较,一旦循环变量等于0,结束条件就会变为假,节约多达50%的执行时间!
for-in循环比其他循环慢,请在处理需要遍历的对象属性集或JSON对象的未知属性集时才采用它
进一步优化循环–展开循环:
使一次循环完成多次循环的工作
var iterations=Math.ceil(values.length/8);//根据经验,8是最佳数值,确定循环次数 var startAt=values.length%8;//要额外处理的数组项数量,即8的余数,仅在第一次循环中使用,使用完后,重置为0 var i=0; do{ switch(startAt){ case 0:process(values[i++]); case 7:process(values[i++]); case 6:process(values[i++]); case 5:process(values[i++]); case 4:process(values[i++]); case 3:process(values[i++]); case 2:process(values[i++]); case 1:process(values[i++]); } startAt=0; }while(--iteration>0)
3.字符串优化
字符串连接:
字符串连接一直是JavaScript中性能最低的操作之一。
通常情况下的加法运算:
var text='hello'; text+=' '; text+='world';
这意味着要创建中间字符串来存储连接的结果,频繁地在后台创建和销毁字符串会导致字符串连接的性能异常底下。
开发者利用了JavaScript的Array数组来补救:
var buffer=[],i=0; buffer[i++]='hello'; buffer[i++]=' ';//通过相应的索引值直接添加元素比调用push方法略快一点。 buffer[i++]='world'; var text=buffer.join('');
不过,如今浏览器对字符串的优化已经改变了字符串连接的局面。IE8+、ff、safari、chrome、opera已经对加法运算做了优化使其比数组运算法更加快速。当字符串相对较小(少于20个字符)且连接的数量也较少时(少于1000个),所有浏览器使用加法运算符都能在不到1毫秒之内轻松完成连接。但增加连接字符串的数量或大小时,在IE7中性能会明显下降。在FF下,当字符串大小增加时,加法运算符和数组技术的性能差异会变小。在Safari下,当字符串连接数量增加时,这两种技术的性能差异也会同样变小。只有在chrome和opera下,加法运算符一直保持着显著的性能优势。所以,需要基于用户的浏览器来权衡使用哪种技术。当然,大多数情况下,加法运算符是首选。
裁剪字符串:
JavaScript没有用于移除字符串头尾空白的原生修剪方法。
用于弥补的函数:
function trim(text){ return text.replace(/^\s+|\s+$/g,""); }
但是,这个函数可以在正则表达式上优化性能。
对性能的影响来自于正则表达式的两个方面:一个方面是指明有两个匹配模式的管道运算符,另一方面是指明全局应用该模式的g标记。保持正则表达式尽可能的简单,可以提高性能。
Steven Levithan提出的在JavaScript中执行速度最快的裁剪字符串方式:
function trim(text){ text=text.replace(/^\s+/,"");//删除头部的空白 for(var i=text.length-1;i>=0;i--){//清除尾部的空白 if(/\S/.test(text.charAt(i))){ text=text.substring(0,i+1); break; } } return text; }
4.避免运行时间过长的脚本
JavaScript是单线程语言。所以在代码执行时会导致页面被冻结而出现假死。在一个时间段中,每个窗口或标签页都只能执行一个脚本,同时,所有用户的交互被中断。如果JavaScript代码未经过细心的设计,有可能长时间的冻结页面,而导致浏览器停止响应。最常见的脚本执行时间过长的原因包括:过多的DOM交互、过多的循环、过多的递归。
在复杂的WEB应用程序中,为了避免长时间的页面冻结而导致不能进行交互,需要人为地插入中断。
解决方案:使用定时器挂起。
window.onload=function(){ //页面加载完成 //创建第一个定时器 setTimeout(function(){ //被延迟的脚本1 setTimeout(function(){ //被延迟的脚本2 },100); //被延迟的脚本1,继续执行 },100); }
实际上就是把某些代码排到JavaScript引擎队列中稍后执行,而页面可以利用这段引擎挂起的时间来进行交互。同样也可将定时器应用于大型数组处理中
最后,推荐下这本书:
相关文章推荐
- [实战分析] 编写高效的JavaScript程序
- 66. 编写高效的 JavaScript
- 关于编写性能高效的javascript事件的技术[转] 来源:酷勤网 发布于 2015-2-12
- 关于编写性能高效的javascript事件的技术
- 关于编写性能高效的javascript事件的技术
- 关于编写性能高效的javascript事件的技术
- 编写高效JavaScript的20条常规建议
- 关于编写性能高效的javascript事件的技术
- 关于编写性能高效的javascript事件的技术
- Web前端性能优化——编写高效的JavaScript
- 关于编写性能高效的javascript事件的技术
- 编写高效的JavaScript程序
- 编写高效的JavaScript程序
- 编写快速、高效的JavaScript代码
- 编写高效的JavaScript程序
- 编写快速、高效的JavaScript代码
- 关于编写性能高效的javascript事件的技术
- 编写快速、高效的JavaScript代码
- 关于编写性能高效的javascript事件的技术
- [实战分析] 编写高效的JavaScript程序