js优化原则

首先,与其他语言不同,JS的效率很大程度是取决于JS engine的效率。除了引擎实现的优劣外,引擎自己也会为一些特殊的代码模式采取一些优化的策略。例如FF、Opera和Safari的JS引擎,都对字符串的拼接运算(+)做了特别优化。显然,要获得最大效率,就必须要了解引擎的脾气,尽量迎合引擎的口味。所以对于不同的引擎,所作的优化极有可能是背道而驰的。

而如果做跨浏览器的web编程,则最大的问题是在于IE6(JScript 5.6)!因为在不打hotfix的情况下,JScript引擎的垃圾回收的bug,会导致其在真实应用中的performance跟其他浏览器根本不在一个数量级上。因此在这种场合做优化,实际上就是为JScript做优化!

所以第一原则就是只需要为IE6(未打补丁的JScript 5.6或更早版本)做优化

如果你的程序已经优化到在IE6下可以接受的性能,那基本上在其他浏览器上性能就完全没有问题。

因此,注意我下面讲的许多问题在其他引擎上可能完全不同,例如在循环中进行字符串拼接,通常认为需要用Array.join的方式,但是由于SpiderMonkey等引擎对字符串的“+”运算做了优化,结果使用Array.join的效率反而不如直接用“+”!但是如果考虑IE6,则其他浏览器上的这种效率的差别根本不值一提。

JS优化与其他语言的优化也仍然有相同之处。比如说,不要一上来就急吼吼的做优化,那样毫无意义。优化的关键,仍然是要把精力放在最关键的地方,也就是瓶颈上。一般来说,瓶颈总是出现在大规模循环的地方。这倒不是说循环本身有性能问题,而是循环会迅速放大可能存在的性能问题。

所以第二原则就是以大规模循环体为最主要优化对象

以下的优化原则,只在大规模循环中才有意义,在循环体之外做此类优化基本上是没有意义的。

目前绝大多数JS引擎都是解释执行的,而解释执行的情况下,在所有操作中,函数调用的效率是较低的。此外,过深的prototype继承链或者多级引用也会降低效率。JScript中,10级引用的开销大体是一次空函数调用开销的1/2。这两者的开销都远远大于简单操作(如四则运算)。

所以第三原则就是尽量避免过多的引用层级和不必要的多次方法调用

特别要注意的是,有些情况下看似是属性访问,实际上是方法调用。例如所有DOM的属性,实际上都是方法。在遍历一个NodeList的时候,循环条件对于nodes.length的访问,看似属性读取,实际上是等价于函数调用的。而且IE DOM的实现上,childNodes.length每次是要通过内部遍历重新计数的。(My god,但是这是真的!因为我测过,childNodes.length的访问时间与childNodes.length的值成正比!)这非常耗费。所以预先把nodes.length保存到js变量,当然可以提高遍历的性能。

同样是函数调用,用户自定义函数的效率又远远低于语言内建函数,因为后者是对引擎本地方法的包装,而引擎通常是c,c++,java写的。进一步,同样的功能,语言内建构造的开销通常又比内建函数调用要效率高,因为前者在JS代码的parse阶段就可以确定和优化。

所以第四原则就是尽量使用语言本身的构造和内建函数

这里有一个例子是高性能的String.format方法。String.format传统的实现方式是用String.replace(regex, func),在pattern包含n个占位符(包括重复的)时,自定义函数func就被调用n次。而这个高性能实现中,每次format调用所作的只是一次Array.join然后一次String.replace(regex, string)的操作,两者都是引擎内建方法,而不会有任何自定义函数调用。两次内建方法调用和n次的自定义方法调用,这就是性能上的差别。

同样是内建特性,性能上也还是有差别的。例如在JScript中对于arguments的访问性能就很差,几乎赶上一次函数调用了。因此如果一个可变参数的简单函数成为性能瓶颈的时候,可以将其内部做一些改变,不要访问arguments,而是通过对参数的显式判断来处理。

比如:

Java代码  

  1. function sum() {
  2. var r = 0;
  3. for (var i = 0; i < arguments.length; i++) {
  4. r += arguments[i];
  5. }
  6. return r;
  7. }

这个sum通常调用的时候个数是较少的,我们希望改进它在参数较少时的性能。如果改成:

Java代码  

  1. function sum() {
  2. switch (arguments.length) {
  3. case 1: return arguments[0];
  4. case 2: return arguments[0] + arguments[1];
  5. case 3: return arguments[0] + arguments[1] + arguments[2];
  6. case 4: return arguments[0] + arguments[1] + arguments[2] + arguments[3];
  7. default:
  8. var r = 0;
  9. for (var i = 0; i < arguments.length; i++) {
  10. r += arguments[i];
  11. }
  12. return r;
  13. }
  14. }

其实并不会有多少提高,但是如果改成:

Java代码  

  1. function sum(a, b, c, d, e, f, g) {
  2. var r = a ? b ? c ? d ? e ? f ? a + b + c + d + e + f : a + b + c + d + e : a + b + c + d : a + b + c : a + b : a : 0;
  3. if (g === undefined) return r;
  4. for (var i = 6; i < arguments.length; i++) {
  5. r += arguments[i];
  6. }
  7. return r;
  8. }

就会提高很多(至少快1倍)。

最后是第五原则,也往往是真实应用中最重要的性能障碍,那就是尽量减少不必要的对象创建

本身创建对象是有一定的代价的,但是这个代价其实并不大。最根本的问题是由于JScript愚蠢之极的垃圾回收调度算法,导致随着对象个数的增加,性能严重下降(据微软的人自己说复杂度是O(n^2))。

比如我们常见的字符串拼接问题,经过我的测试验证,单纯的多次创建字符串对象其实根本不是性能差的原因。要命的是在对象创建期间的无谓的垃圾回收的开销。而Array.join的方式,不会创建中间字符串对象,因此就减少了那该死的垃圾回收的开销。

因此,如果我们能把大规模对象创建转化为单一语句,则其性能会得到极大的提高!例如通过构造代码然后eval——实际上PIES项目中正在根据这个想法来做一个专门的大规模对象产生器……

好了上面就是偶总结的JS优化五大原则。

时间: 2024-10-01 21:36:08

js优化原则的相关文章

MySQL 索引优化原则

一.索引优化原则 1.最左前缀匹配原则,联合索引,mysql会从做向右匹配直到遇到范围查询(>.<.between.like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整. 2.=和in可以乱序,比如a = 1 and b = 2 and c = 3 建立(a,b,c)索引可以任意顺序,mysql的查询优化器会帮你优

前端js优化方案(连续更新)

最近在读<高性能javascript>,在这里记录一下读后的一些感受,顺便加上自己的一些理解,如果有兴趣的话可以关注的我的博客http://www.bloggeng.com/,我会不定期发布一些前端教程还有前端干货,话不多说,进入我们的正题 一.js优化之加载 1.script标签放在底部,不要放在head标签: 2.尽量减少js文件数量 3.给script标签添加一个defer属性,defer属性指明所含的脚本不会修改DOM,因此代码能安全地延迟执行. <script type=&qu

Joomla T3模板启用CSS、JS优化

如何优化生成后的文件 当启用了优化选项,CSS和JS优化文件将在一个页面第一次被加载时自动生成.如果CSS或JS有改动,新生成的优化文件也会自动生成. 生成优化文件路径: XXX/t3-assets/css XXX/t3-assets/js XXX:项目名称

Js编程原则和良好习惯

1.预留退路:在禁止Js或者Js不被支持的情况下,网页还能正常工作.也就是说,虽然某些功能无法使用,但最基本的操作仍能顺利完成. 案例:点击链接,打开一个新窗口.就如本站的登录(弹出一个模拟窗口),与其让用户在点击链接的时候被带离当前页面,不如让用户仍停留在当前页面,并用一个弹出窗口来显示相关信息,这无疑是一种更好的解决方法.一些错误的写法:伪协议:<a href="javascript:showWindow('login', this.href);" >登录</a&

r.js优化前端(摘抄)

r.js是requireJS的优化(Optimizer)工具,可以实现前端文件的压缩与合并,在requireJS异步按需加载的基础上进一步提供前端优化,减小前端文件大小.减少对服务器的文件请求.要使用r.js需下载r.js文件(点我下载),将其放到你的项目根目录:还需要安装nodeJS(点我下载),以便通过命令行来执行r.js功能.我们将拿一个小案例来详细说明使用r.js的方法(你可以点此下载这个案例). 如下图所示的项目(见案例中的before文件夹)仅仅使用了requireJS,但还未使用过

高效C#编码优化原则

本文汇总了高效C#编码常见的优化原则,对于进行C#程序设计来说有很大的参考借鉴作用.具体列出如下: 1.foreach VS for 语句 Foreach 要比for具有更好的执行效率 Foreach的平均花费时间只有for的30%.通过测试结果在for和foreach都可以使用的情况下,我们推荐使用效率更高的foreach 另外,用for写入数据时间大约是读取数据时间的10倍左右. 2.避免使用ArrayList ArrayList的性能低下任何对象添加到ArrayList中都要封箱为Syst

Flex内存泄露解决方法和内存释放优化原则

本文向大家简单介绍一下Flex内存泄露问题,主要包括Flex内存释放优化原则和Flex内存泄露解决方法两大部分内容,希望你会感兴趣. 作者:vipoyb来源:csdn.net|2010-07-29 14:08   你对Flex内存泄露的概念是否了解,这里和大家分享一下Flex内存释放优化原则和Flex内存泄露解决方法,希望本文的介绍能让你有所收获. Flex内存释放优化原则 1.被删除对象在外部的所有引用一定要被删除干净才能被系统当成垃圾回收处理掉: 2.父对象内部的子对象被外部其他对象引用了,

hbase表设计优化原则 ***** 生产环境中使用小结

2019/2/28 星期四 hbase表设计优化原则 https://www.cnblogs.com/qingyunzong/p/8696962.html表设计1.列簇设计 追求的原则是:在合理范围内能尽量少的减少列簇就尽量减少列簇. 最优设计是:将所有相关性很强的 key-value 都放在同一个列簇下,这样既能做到查询效率 最高,也能保持尽可能少的访问不同的磁盘文件. 以用户信息为例,可以将必须的基本信息存放在一个列族,而一些附加的额外信息可以放在 另一列族.2.RowKey 设计 HBas

数据库优化原则

最近数据库课程设计,我总结了一下数据库的优化方法,希望对有需要的人能有帮助: 1.对查询进行优化,尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如: select id from p where num is null 可以在num上设置默认值0,确保表中num列没有null值,然后这样查询: select id from p where num=