提高JavaScript性能
JavaScript是一种解释型的语言,执行速度肯定比编译型的语言要慢得多:
比编译好的C慢5000倍
比解释型的java慢100倍
比解释型的perl慢10倍
而且JavaScript相比桌面应用程序只能访问较少的内存和CPU周期。虽然从2005年开始,浏览器在JavaScript执行性能方面做了很多工夫,但它还是比其它语言慢得多。不过,还是有改进代码的整体性能的方法的。
1、作用域上做文章
我们知道JavaScript的作用域以及作用域链的运作,随着作用域链中的作用域数量的增加,访问当前作用域外的变更的时间也是在增加的。因为访问全局变量需要遍历作用域链,所以要比访问局部变量要慢。也就是说,减少花费在遍历作用域链上的时间就能增加整体脚本的性能了。
function updateUI(){ var imgs = documetn.getElementsByTagName("img"); for (var i = 0,len = imgs.lengs; i < len; i++){ imgs[i].title = document.title + " image " + i; } var msg = document.getElementById("msg"); msg.innerHTML = "Update complete."; } function updateUI2(){ var doc = document; var imgs = doc.getElementsByTagName("img"); for (var i = 0,len = imgs.lengs; i < len; i++){ imgs[i].title = document.title + " image " + i; } var msg = document.getElementById("msg"); msg.innerHTML = "Update complete."; }
上面的函数如果页面上有多个图片,那么for循环的document引用就会被执行多次,每次都会进行作用域链的查找。下面的函数通过 创建一个指向document对象的局部变量,就可以限制一次全局查找来改进函数的性能。
还有就是避免使用with语句。因为和函数类似,这个语句会创建自己的作用域,因此会增加其中执行的作用域链的长度。
2、选择正确的算法
性能问题一部分是和用于解决问题的算法是有关的,成熟的开发人员根据经验可以很好的选择算法获得更好的性能。
一般的数组访问以及简单的变量查找都是效率最高的(O(1)),当然了遍历整个数组中的元素的复杂度为O(n),访问对象上的属性也是O(n)的复杂度。所以说,一旦多次用到对象的属性,应该将其存储在局部变量中,用局部变量将属性查找替换为变量的查找,从而减少算法的复杂度。
再有就是优化循环:
循环是编程中是最为常见的结构,优化循环是性能优化中很重要的一个部分。
减值迭代:大多数循环使用一个从0开始、增加到某个特定值的迭代器。在很多情况下,从最大值开始,在循环中不断减值的迭代器更加高效。
简化终止条件:如前所说,属性查找或者其它O(n)的操作不应该出现在终止条件这个地方。
简化循环体:循环体是执行最多的,一定要确保没有某些可以被很容易移出循环的密集计算。
使用后测试循环:最常用的for循环和while循环都是前测试循环,而如do-while为后测试循环,可以避免最初终止条件的计算,因此运行更快。
当循环的次数是确定的,不用循环往往更快。如:数组有三个元素,直接对数组操作,展开循环可以消除建立循环和处理终止条件的额外开销。如果循环中的迭代数不能事先确定,那可以使用一种叫做Duff装置的技术。这个技术是以其创建者Tom Duff命名的,最早在C语言中使用这项技术。Jeff Greenberg用javascript实现了Duff装置。基本概念是通过计算迭代的次数是否为8的倍数将一个循环展开为一系列语句。
//credit: Jeff Greengerg for JS implementation of Duff's Device var iterations = Math.floor(values.length / 8 ); var startAt = values.length % 8 ; 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(-- iterations > 0 );
Duff装置的实现是通过将values数组中元素个数除以8来计算出循环需要进行多少次迭代,然后使用取整的下限函数确保结果是整数。当然,可能会有一些不能被处理到的元素,这个数量保存在startAt变量中,首次执行会对其进行额外的调用 。
由Andrew B. King在Speed Up Your Site(New Riders,2003)提出更快的Duff装置:
//credit :Speed Up Your Site (New Riders,2003) var iterations = Math.floor(values.length /8 ); var leftover = value.length % 8; var i=0; if(leftover >0){ do{ process(values[i++]); }while(--leftover >0); } do { process(values[i++]); process(values[i++]); process(values[i++]); process(values[i++]); process(values[i++]); process(values[i++]); process(values[i++]); process(values[i++]); }while(--iterations > 0);
这个方法几乎比原始的Duff装置实现快40%。
对于大数值量使用展开循环可以节省很多时间,小数据量,额外的开销则划不来了。
当使用eval()函数或者是Function构造函数以及使用setTimeout()传入字符串参数时都会出现双重解释。这些操作是不能在初始的解析过程中完成的,需要在代码运行的时候新启动一个解析器来解析新的代码。
eval("alert('hello')"); var sayHello = new Function("alert('hello')"); setTimeout("alert('hello')",500);
如非必须,应该尽量避免使用。
最后,应该尽量使用原生方法,如果有方法可以使用,就不要自己写一个方法了,因为这些方法是c/c++之类的编译语言写出来的;如果有一系列复杂的if-else语句,应该换成switch,这样比较快;运算的时候,如果可以使用位运算的,尽量使用位运算。
3、最小化语句语句
JavaScript代码中的语句数量也会影响所执行的操作的速度,所以可以组合在一起的语句,以减少脚本整体的执行时间。
var a = "a"; var b= "b"; var c="c"; var d="d", e="e", f="f";
声明变量时,使用单个var声明比多个var声明好。
var name = values[i]; i++; //better var name = values[i++];
可以合并的语句应该尽量合并。
var values = new Array(); value[0] = "a"; value[1] = "b"; value[2] = "c"; //better var value = ["a","b","c"] var person = new Object(); person.name = "welpher"; person.age = "25"; person.sayHello = function(){ alert("hello"); }; //better var person = { name : "welpher", age : "25", sayHello:function(){ alert("hello"); } };
使用数组和对象字面量,不过在ie6及更早的版本中使用字面量有微小的性能惩罚。
4、优化DOM交互
我们知道,DOM是最慢的一部分。DOM交互要消耗大量时间,因为它们往往要重新渲染整个页面或者某一部分。这部分后面有时间再详细研究。
建议继续学习:
- Xvfb+YSlow+ShowSlow搭建前端性能测试框架 (阅读:54187)
- 30分钟3300%性能提升――python+memcached网页优化小记 (阅读:12110)
- Go Reflect 性能 (阅读:9723)
- 长连接(KeepAlive)在 http 连接中的性能影响 (阅读:7029)
- SQL vs NoSQL:数据库并发写入性能比拼 (阅读:6610)
- 服务器性能测试工具推荐 (阅读:6437)
- WEB性能测试工具推荐 (阅读:5629)
- 分析进程内存分配情况,解决程序性能问题 (阅读:5328)
- 由12306.cn谈谈网站性能技术 (阅读:4910)
- [调优] Squid 不同版本的性能对比 (阅读:4163)
扫一扫订阅我的微信号:IT技术博客大学习
- 作者:welpher 来源: 前端码工
- 标签: 性能
- 发布时间:2016-04-02 14:09:17
- [66] Go Reflect 性能
- [66] Oracle MTS模式下 进程地址与会话信
- [65] 如何拿下简短的域名
- [59] IOS安全–浅谈关于IOS加固的几种方法
- [59] android 开发入门
- [59] 图书馆的世界纪录
- [58] 【社会化设计】自我(self)部分――欢迎区
- [53] 视觉调整-设计师 vs. 逻辑
- [47] 界面设计速成
- [47] 读书笔记-壹百度:百度十年千倍的29条法则