在 上一篇 中,从HTTP请求到页面渲染几个方面对提升网站性能提出了几点建议,本文是学习Steve Sounders
的另一本书《高性能网站建设进阶指南》以后,从JavaScript性能的角度进行总结归纳,诸君共勉。html
JavaScript性能
是实现高性能Web应用程序的关键
——Steve Sounders编程
当执行一段JavaScript代码(全局代码或函数)时,JavaScript引擎会建立为其建立一个做用域
又称为执行上下文
(Execution Context),在页面加载后会首先建立一个全局的做用域,而后每执行一个函数,会创建一个对应的做用域,从而造成了一条做用域链。每一个做用域都有一条对应的做用域链,链头是全局做用域,链尾是当前函数做用域。数组
做用域链的做用是用于解析标识符,当函数被建立时(不是执行),会将this、arguments、命名参数和该函数中的全部局部变量添加到该当前做用域中,当JavaScript须要查找变量X的时候(这个过程称为变量解析
),它首先会从做用域链中的链尾也就是当前做用域进行查找是否有X属性,若是没有找到就顺着做用域链继续查找,直到查找到链头,也就是全局做用域链,仍未找到该变量的话,就认为这段代码的做用域链上不存在x变量,并抛出一个引用错误(ReferenceError)的异常。dom
管理好做用域链的深度,是一种只要少许工做就能提升性能的简易方法,咱们应避免因无心中增加了做用域链而致使执行速度变得缓慢。编程语言
若是理解了做用域链的概念,那么咱们应该清楚JavaScript引擎对变量的解析时间跟做用域链的深度有关,显而易见,局部变量因为处于链尾,存取速度是最快的,所以,一个好的经验是:任何非局部变量使用超过一次时,请使用局部变量将其存储下来,例如:函数
function changeDiv(){ document.getELementById('myDiv').className = 'changed'; document.getELementById('myDiv').style.height = 150; }
这里myDiv这个dom元素被引用了两次,为了更快的引用,咱们应该用一个局部变量将其存储下来,这样作的好处不只缩短了做用域链,并且避免了DOM元素的重复查询:性能
function changeDiv(){ var myDivStyle = document.getElementById('myDiv').style; myDiv.className = 300; myDiv.style.height = 150; }
通常在代码执行过程当中,函数的做用域链是固定的,然而with能够临时增加函数的做用域链。with用于将对象属性做为局部变量来显示,使其便于访问,例如:学习
var user = { name:'vicfeel', age:'23' }; function showUser(){ var local = 0; with(user){ console.log("姓名" + name); console.log("年龄" + age); console.log(local); } } showUser();
这个例子中,经过with在showUser做用域链的链尾中又增长了一个临时做用域,该做用域存储着user对象的全部属性,也就是增加了with这段代码的做用域链,在这段代码中,局部变量像local从链尾的第一个对象变成了第二个,天然减慢了标识符的存取。直到with语句结束,做用域链恢复增加。正由于with的这个缺陷,咱们应尽可能避免使用with关键字。优化
JavaScript与其它编程语言同样,拥有一些流控制语句(循环、条件等),在每一个环节上使用恰当的语句能极大的提升脚本的运行速度。网站
提到条件判断,首先要避免的一种使用方式:
if(value == 0){ return result0; } else if(value == 1){ return result1; } else if(value == 2){ return result2; } else if(value == 3){ return result3; } else if(value == 4){ return result4; } else if(value == 5){ return result5; } else if(value == 6){ return result6; } else{ return result7; }
这种使用if进行条件判断的方式存在的主要问题是层次太深,当我要value = 7时,消耗时间要比value = 0长不少,大大损耗了性能,同时可读性不好。
一种更好的方式,利用switch进行判断。
switch(value){ case 0: return result0; case 1: return result1; case 2: return result2; case 3: return result3; case 4: return result4; case 5: return result5; case 6: return result6; default: return result7; }
这样不只提升了可读性,查询时间也要比if更快。可是若是只有一两个条件时,if是比switch更快的
在JavaScript中,条件查询还有另一种方式,以前的例子是根据值返回不一样的值,恰好能够利用数组实现hash表的映射查询。
//定义数组 var results = [result0,result1,result2,result3,result4,result5,result6,result7]; //查询结果 return results[value];
这种数组的方式,在查询范围很大时才更加有效,由于它没必要检测上下边界,只须要填入索引值就能够查询了。它的局限性在于条件对应的是单一值,而不是一系列操做。所以要综合实际状况,选择合适的条件判断方式,发挥性能最大化。
JavaScript中存在4种循环方式for循环、do-while循环、while循环和for-in循环。下面是一个很经常使用的循环使用方式:
var values = [1,2,3,4,5]; for(var i = 0;i < values.length;i++){ process(values[i]); }
咱们能够看到,这段代码最明显能够优化的地方在于values.length,每次循环i都要和values的长度进行比较,而查询属性要比局部变量更耗时,若是循环次数越大,这种耗时就越明显,所以能够这样优化:
var values = [1,2,3,4,5]; var length = values.length;//局部变量存储数组长度 for(var i = 0;i < length;i++){ process(values[i]); }
这段代码还能够继续优化,将循环变量递减到0,而不是递加到总长度。
var values = [1,2,3,4,5]; var length = values.length; for(var i = length;i--;){ //递减到0 process(values[i]); }
这里将循环结束改造为与0比较,因此每一个循环的速度更快了,根据循环的复杂度不一样,这种简单改变能够比原来节约大概50%的时间。
博文做者:vicfeel
博文出处:http://www.cnblogs.com/vicfeel 本文版权归做者和博客园共有,欢迎转载,但须保留此段声明,并给出原文连接,谢谢合做! 若是阅读了本文章,以为有帮助,您能够为个人博文点击“推荐一下”!