stb前端开发js性能优化总结

   js性能优化

  javascript是一种解释型语言,性能无法达到和C、C++等编译语言的水平,但还是有一些方法来改进。

  1、循环

  JavaScript中的循环方式有for(;;)、while()、for(in)3种。其中for(in)的效率极差,因为for(in)执行过程中需要查询散列键。for(;;)和while()比较,while循环的效率要优于for(;;)。

  2、局部变量和全局变量

  局部变量的访问速度更快,因为全局变量其实是全局对象的成员,而局部变量是放在函数的堆栈当中的。

  3、不使用eval

  使用eval函数相当于在运行时再次调用解释引擎对内容进行解释运行

  4、减少对象查找

  因为JavaScript的特性,对于类是表达式a.b.c.d.e,需要至少4次查询操作。首先检查a在检查a中的b,如此往下。应尽量避免出现这样的表达式、可以利用局部变量把要访问的最终结果放入一个临时的位置进行查询。

  这一点可以和循环结合起来,例如对一个数组可以先取他的长度 var len = a.length

  ##其实java 中对于列表的循环也是先取size给一个临时变量

  5、字符串连接

  如果是追加字符串,最好使用s+=anotherStr操作,而不要使用s=s+""

  但是如果要连接多个字符串,应该少用+= 例如:

  java 代码

  s+=a;

  s+=b;

  s+=c;

  应该写成 s+=a+b+c;

  如果是收集字符串,比如收集字符串,最好使用一个缓存实现。具体的实现思路就是使用Javascript数组来收集每个字符串,最好使用join方法将这些字符串连接起来,如下面代码所示:

  var buf = new Array();

  for(var i=0;i<100;i++){

  buf.push(i.toString());

  }

  var all = buf.join("");

  6、类型转换

  类型转换是JavaScript编程中容易出错的地方,因为JavaScript是动态类型语言,即弱类型语言,不能指定变量的具体类型。

  1、把数字转换成字符串,应用""+1,虽然比较别扭一点、但效率是最高的

  (""+)>String()>.toString()>newString()

  String()属于内部函数,所以速度很快,toString()要查询原型中的函数,new String()用于返回一个精确的副本。

  2、浮点数转换成整型 parseInt()用于将字符串转换成数字,应该使用Math.floor()或者Math.round()来实现浮点型和整型之间的转换。

  3、对于自定义的对象,如果定义了toString()方法进行类型转换的话,推荐显示调用toString()

  7、使用直接量

  以往我们都使用new Array(parm,parm1..)等形式,对于直接量的解释JavaScript支持使用[param,param1....]来直接表达一个数组。

  前一种方式调用Array内部构造器,而后一种方式是解释引擎直接解释的,故执行速度要略微快一点。同理var foo = {}比 var foo = new Object()快,var reg=/..../比 var reg=new RegExp()执行的快些。

  8、字符串遍历

  优先使用正则表达式

  9、高级对象

  自定义高级对象和Date、RegExp等对象构造时会消耗大量的时间和资源

  10、插入HTML

  document.write效率较低,innerHTML效率较高

  11、下标查询

  使用直接的下标查找一个对象的属性比通过.name方法要快很多

  12、创建DOM节点

  通常我们可能会使用字符串直接写HTML语句来创建节点,实际上这样有如下缺点:

  1、无法保证代码的有效性;

  2、字符串操作效率低。

  应该使用documeng.createElement()方法。如果存在现成的样板节点,应该使用cloneNode()方法。

  所以第一原则就是只需要为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代码

  function sum() {

  varr = 0;

  for (var i = 0; i < arguments.length; i++) {

  r += arguments[i];

  }

  return r;

  }

  function sum() {

  var r = 0;

  for (var i = 0; i < arguments.length; i++) {

  r+= arguments[i];

  }

  return r;

  }

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

  Java代码

  function sum() {

  switch (arguments.length) {

  case 1: return arguments[0];

  case 2: return arguments[0] + arguments[1];

  case 3: return arguments[0] + arguments[1] + arguments[2];

  case 4: return arguments[0] + arguments[1] + arguments[2] +arguments[3];

  default:

  var r = 0;

  for (var i = 0; i < arguments.length; i++) {

  r += arguments[i];

  }

  return r;

  }

  }

  function sum() {

  switch (arguments.length) {

  case 1: return arguments[0];

  case 2: return arguments[0] + arguments[1];

  case 3: return arguments[0] + arguments[1] + arguments[2];

  case 4: return arguments[0] + arguments[1] + arguments[2] +arguments[3];

  default:

  var r = 0;

  for (var i = 0; i < arguments.length; i++) {

  r += arguments[i];

  }

  return r;

  }

  }

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

  Java代码

  function sum(a, b, c, d, e, f, g) {

  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;

  if (g === undefined) return r;

  for (var i = 6; i < arguments.length; i++) {

  r += arguments[i];

  }

  return r;

  }

  function sum(a, b, c, d, e, f, g) {

  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;

  if(g === undefined) return r;

  for (var i = 6; i < arguments.length; i++) {

  r+= arguments[i];

  }

  return r;

  }

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

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

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

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

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

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

  除了这些原则以外,还有一些特殊情况,如DOM的遍历,以后有时间再做讨论。

时间: 2024-09-29 18:49:04

stb前端开发js性能优化总结的相关文章

前端工程与性能优化之静态资源版本更新与缓存

每个参与过开发企业级web应用的前端工程师或许都曾思考过前端性能优化方面的问题.我们有雅虎 14条性能优化原则,还有两本很经典的性能优化指导书:<高性能网站建设指南>.<高性能网站建设 进阶指南>.经验丰富的工程师对于前端性能优化方法耳濡目染,基本都能一一列举出来.这些性能优 化原则大概是在7年前提出的,对于web性能优化至今都有非常重要的指导意义. 然而,对于构 建大型web应用的团队来说,要坚持贯彻这些优化原则并不是一件十分容易的事.因为优化原则中很多 要求是与工程管理相违背的

Android编程开发之性能优化技巧总结_Android

本文详细总结了Android编程开发之性能优化技巧.分享给大家供大家参考,具体如下: 1.http用gzip压缩,设置连接超时时间和响应超时时间 http请求按照业务需求,分为是否可以缓存和不可缓存,那么在无网络的环境中,仍然通过缓存的httpresponse浏览部分数据,实现离线阅读. 2.listview 性能优化 1).复用convertView 在getItemView中,判断convertView是否为空,如果不为空,可复用.如果couvertview中的view需要添加listern

Android编程开发之性能优化技巧总结

本文详细总结了Android编程开发之性能优化技巧.分享给大家供大家参考,具体如下: 1.http用gzip压缩,设置连接超时时间和响应超时时间 http请求按照业务需求,分为是否可以缓存和不可缓存,那么在无网络的环境中,仍然通过缓存的httpresponse浏览部分数据,实现离线阅读. 2.listview 性能优化 1).复用convertView 在getItemView中,判断convertView是否为空,如果不为空,可复用.如果couvertview中的view需要添加listern

Android高级开发之性能优化典范

本章介绍android高级开发中,对于性能方面的处理.主要包括电量,视图,内存三个性能方面的知识点. 1.视图性能 (1)Overdraw简介 Overdraw就是过度绘制,是指在一帧的时间内(16.67ms)像素被绘制了多次,理论上一个像素每次只绘制一次是最优的,但是由于重叠的布 局导致一些像素会被多次绘制,而每次绘制都会对应到CPU的一组绘图命令和GPU的一些操作,当这个操作耗时超过16.67ms时,就会出现掉帧现象,表现为应用卡顿,所以对重叠不可见元素的重复绘制会产生额外的开销,需要尽量减

前端工程与性能优化之静态资源管理与模板框架

本系列文章从一个全新的视角来思考web性能优化与前端工程之间的关系,通过解读百度前端集成解 决方案小组(F.I.S)在打造高性能前端架构并统一百度40多条前端产品线的过程中所经历的技术尝试 ,揭示前端性能优化在前端架构及开发工具设计层面的实现思路. 在上一部分,我们介绍了静 态资源版本更新与缓存.今天的部分将会介绍静态资源管理与模板框架的用法. 静态资源管理与模板框架 让我们再来看看前面的优化原则表还剩些什么: 很不幸,剩下的优化原则都 不是使用工具就能很好实现的.或许有人会辩驳:"我用某某工具

JS性能优化笔记搜索整理_javascript技巧

通过网上查找资料了解关于性能优化方面的内容,现简单整理,仅供大家在优化的过程中参考使用,如有什么问题请及时提出,再做出相应的补充修改. 一. 让代码简洁:一些简略的表达方式也会产生很好的优化 eg:x=x+1;在不影响功能的情况下可以简写为x++; 二. 变量名方法名尽量在不影响语意的情况下简单.(可以选择首字母命名) eg:定义数组的长度可以取名为:ArrLen而不需要取为ArrayLength. 三. 关于JS的循环,循环是一种常用的流程控制. JS提供了三种循环:for(;;).while

Android高级开发之性能优化典范_Android

本章介绍android高级开发中,对于性能方面的处理.主要包括电量,视图,内存三个性能方面的知识点. 1.视图性能 (1)Overdraw简介     Overdraw就是过度绘制,是指在一帧的时间内(16.67ms)像素被绘制了多次,理论上一个像素每次只绘制一次是最优的,但是由于重叠的布 局导致一些像素会被多次绘制,而每次绘制都会对应到CPU的一组绘图命令和GPU的一些操作,当这个操作耗时超过16.67ms时,就会出现掉帧现象,表现为应用卡顿,所以对重叠不可见元素的重复绘制会产生额外的开销,需

如何写出高效的JavaScript JS性能优化窍门

本文我们来讨论一下JavaScript性能优化. Firefox拥有目前最快的JavaScript解析器 SpiderMonkey,有各种各样的让JavaScript的速度更快的努力,其中一个是asm.js. Asm.js是JavaScript是由Emscripten产生的一个子集,它为C/C++编绎成的JavaScript代码做了很多优化,编译型后的代码很难看,这就是为什么你不能自己写优化后的代码,但它运行非常快.我建议你阅读一下这篇文章 好了,我们的目标是写速度更快的JavaScript代码

客户端js性能优化小技巧整理_javascript技巧

下面是一些关于客户端JS性能的一些优化的小技巧: 1. 关于JS的循环,循环是一种常用的流程控制.JS提供了三种循环:for(;;).while().for(in).在这三种循环中 for(in)的效率最差,因为它需要查询Hash键,因此应尽量少用for(in)循环,for(;;).while()循环的性能基本持平.当然,推荐使用for循环,如果循环变量递增或递减,不要单独对循环变量赋值,而应该使用嵌套的++或--运算符. 2. 如果需要遍历数组,应该先缓存数组长度var len=arr.len