js性能优化有哪些方法,提高js性能

  js性能优化有哪些方法,提高js性能

  如何优化JavaScript脚本的性能

  由ShiningRay于2006年4月5日发布

  作者:ShiningRay @ Nirvana工作室

  随着网络的发展,网速和机器速度的提高,越来越多的网站使用富客户端技术。现在Ajax是最流行的方式。JavaScript是一种解释性语言,所以达不到C/Java的水平,这就限制了它在客户端能做什么。为了提高它的性能,我想根据我之前对JavaScript做过的多次测试,谈谈我自己的经验,希望能帮助你提高JavaScript脚本性能。

  语言级

  循环是一种非常常用的控制结构,大部分事情都要靠它来完成。在JavaScript中,我们可以使用for(;),while(),for(in)。其实这三个循环中for(in)的效率极差,因为需要查询哈希键,所以尽量少用。for(;)和while循环性能应该说基本上(平时使用时)相当。

  其实这两个循环怎么用是很有讲究的。我在测试中有一些有趣的情况,见附录。最后的结论是:

  如果循环变量增加或减少,不要单独给循环变量赋值,而是在最后一次读取时使用嵌套的or运算符。

  如果要比较数组的长度,应该提前把数组的length属性放到一个局部变量中,减少查询次数。

  局部变量和全局变量

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

  不使用Eval

  使用eval相当于在运行时调用解释引擎再次运行内容,需要花费大量时间。这时可以使用JavaScript支持的闭包来实现函数模板(闭包的内容请参考函数编程的相关内容)。

  减少对象查找

  由于JavaScript的解释性,a.b.c.d.e至少需要查询4次。先查A,再查A中的B,再查B中的C,依此类推。所以,这样的表达如果重复的话,应该尽量少。你可以使用局部变量,并把它们放在一个临时的地方进行查询。

  这可以和循环结合起来,因为我们经常根据字符串和数组的长度来循环,通常这个长度是恒定的。比如我们每次查询a.length都要进行一次额外的操作,如果我们事先设置了var len=a.length,就少了一次查询。

  字符串的连接

  如果是追加字符串,最好用s=anotherStr,而不是s=anotherstr。

  如果要连接多个字符串,应该使用less=,例如

  s=a;

  s=b;

  s=c;

  应该写成

  s=a b c;

  但是,如果您正在收集字符串,例如多次对同一字符串执行=操作,则最好使用缓存。怎么用?用JavaScript数组收集,最后用join方法连接,如下

  var buf=new Array();

  for(var I=0;i 100i ){

  buf . push(I . tostring());

  }

  var all=buf . join( );

  类型转换是一个常见的错误,因为JavaScript是一种动态类型语言,你不能指定变量的类型。

  1.将数字转换为字符串并应用“1。虽然看起来有点丑,但其实这是最高效的。在性能方面:

  (“”)字符串()。toString()新字符串()

  其实这个和下面的“直接量”差不多。尝试使用编译时可以使用的内部操作比运行时使用的用户操作更快。

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

  2.将浮点数转换成整数,这样更容易出错。很多人喜欢用parseInt()。实际上parseInt()是用来把字符串转换成数字的,而不是浮点数和整数之间的转换。我们应该使用Math.floor()或者Math.round()。

  另外,与第二节的对象搜索问题不同,Math是内部对象,所以Math.floor()实际上并没有太多的查询方法和调用时间,速度是最快的。

  3.对于自定义对象,如果定义了toString()方法进行类型转换,建议显式调用toString(),因为内部操作会在尝试了所有可能性之后,尝试对象的toString()方法是否可以转换为字符串,所以直接调用这个方法会更高效。

  使用直接数量

  其实这个影响比较小,可以忽略。使用直接量是什么意思?例如,JavaScript支持使用[param,param,]来直接表示一个数组。以前我们都是用new Array(param,param,).前者由引擎直接解释,后者调用数组内部构造函数,所以速度略快。

  同样,var foo={}的方式比var foo=new Object()的方式要好;加油,var reg=/./;比var reg=new RegExp()更快。

  字符串遍历操作

  应该用正则表达式来循环字符串,比如替换和搜索,因为JavaScript本身的循环速度比较慢,正则表达式的操作是用C写的语言的API,性能不错。

  高级对象以及Date和RegExp对象将花费大量时间来构建。如果可以重用,就应该缓存。

  DOM相关

  插入HTML

  许多人喜欢使用JavaScript中的document.write来为页面生成内容。其实这是低效的。如果需要直接插入HTML,可以找一个容器元素,比如指定一个div或者span,设置他们的innerHTML,将自己的HTML代码插入到页面中。

  用[""]查询比。items(),这和前面减少对象搜索的思路是一样的。打电话。items()添加了一个查询和函数调用。

  创建DOM节点

  通常,我们可能会使用字符串直接编写HTML来创建节点,但我们确实这样做了。

  字符串操作效率低下。

  因此,应该使用document.createElement()方法,而如果文档中有现成的模板节点,则应该使用cloneNode()方法,因为使用createElement()方法后,需要多次设置元素的属性,使用cloneNode()可以减少3354个属性设置。同样,如果您需要创建许多元素,您应该首先准备一个模板节点。

  如果它的目的是运行代码,你应该使用setInterval而不是setTimeout。SetTimeout一次重置一个计时器。

  据我测试,微软的JScript无论是执行速度还是内存管理,效率都比Mozilla的Spidermonkey差很多,因为JScript现在基本不更新了。但是SpiderMonkey不能使用ActiveXObject。

  文件优化也是非常有效的手段。删除所有空格和注释,把代码放在一行可以加快下载速度。注意是下载速度而不是解析速度。如果是局部的,注释和空格不会影响解释和执行速度。

  本文总结了我在JavaScript编程中发现的一些提高JavaScript性能的方法。事实上,这些经验基于几个原则:

  直接拿现成的东西比较快,比如局部变量比全局变量快,直接变量比运行时构造的对象快等等。

  尽可能减少执行次数,比如先缓存那些需要多次查询的。

  尽可能使用语言的内置特性,比如字符串链接。

  尽量使用系统提供的API,因为这些API都是编译好的二进制代码,执行效率很高。

  同时一些基本的算法优化也可以用在JavaScript中,比如运算结构的调整,这里就不赘述了。但是因为JavaScript是解释型的,所以通常不会在运行时优化字节码,所以这些优化还是很重要的。

  当然,其实这里的一些技巧在其他解释语言中也有使用,你也可以参考一下。

  各种浏览器在http://www.umsu.de/jsperf/的测试和比较

  http://home.earthlink.net/~kendrasg/info/js_opt/

  由于是之前做的测试,测试代码不完整,我添加了如下部分:

  var打印;

  if(文档类型!=未定义){

  print=function(){

  document . write(arguments[0]);

  }else if(typeof WScript!=未定义){

  print=function(){

  WScript。Echo(arguments[0],arguments[1],arguments[2]);

  函数empty(){

  功能基准(f){

  var I=0;

  var start=(new Date()).getTime();

  而(我压力){

  f(一);

  var end=(新日期()).getTime();

  WScript .回声(结束-开始);

  开始=(新日期())。getTime();

  而(i 60000){

  c=[我,我,我,我,我,我,我,我,我,我,我];

  我;

  end=(新日期())。getTime();

  WScript .回声(结束-开始);

  开始=(新日期())。getTime();

  而(i 60000){

  c=新数组(我,我,我,我,我,我,我,我,我,我,我,我,我,我,我,我);

  我;

  var end=(新日期()).getTime();

  WScript .回声(结束-开始);

  函数内部演员(一){

  返回”“我;

  函数字符串转换(i){

  返回字符串

  函数新闻字符串播放(一){

  返回新字符串

  函数toStringCast(i){

  返回I . tostring();

  函数ParseInt(){

  返回parse int(j);

  函数MathFloor(){

  返回数学。地板(j);

  功能楼层(){

  返回楼层(j)和:

  定义变量压力=50000;

  var a=

  var floor=数学. floor

  j=123.123

  打印(-\ n字符串转换测试);

  print(The empty:,benchmark(empty))。

  print(intern:,benchmark(intern cast));

  print( String:);

  基准(字符串强制转换);

  打印(新字符串:);

  基准(newStringCast);

  print( toString:);

  基准(toStringCast);

  打印(-\ n浮点到整数转换测试);

  print( parse int )。

  基准(parse int);

  打印(数学。楼层’);

  基准(数学楼);

  打印("楼层")

  基准(地板);

  函数newObject(){

  返回新对象();

  函数internObject(){

  return { };

  打印(-\ n文字测试);

  打印(运行时新对象,基准(新对象));

  print(文字对象,benchmark(inter对象));

  代码1:

  for(var I=0;i i ){

  arr[I]=0;

  }

  代码2:

  var I=0;

  while(i 100){

  arr[I]=0;

  }

  代码3:

  var I=0;

  while(i 100){

  arr[I]=0;

  我;

  }

  在火狐浏览器下测试这两段代码,结果是代码2优于代码一和3,而代码一一般优于代码3,有时会被代码3超过;而在IE 6.0下,测试压力较大的时候(如测试10000次以上)代码2和3则有时候优于代码1,有时候就会远远落后代码1,而在测试压力较小(如5000次),则代码2代码3代码1。

  代码4:

  var I=0;

  var a;

  while(i 100){

  a=0;

  我;

  }

  代码5:

  var a;

  for(var I=0;i i ){

  a=0;

  }

  上面两段代码在火狐浏览器和工业管理学(工业工程)下测试结果都是性能接近的。

  代码6:

  var a;

  var I=0;

  while(i 100){

  a=I;

  我;

  }

  代码7:

  var a;

  var I=0;

  while(i 100){

  a=I;

  }

  代码8:

  var a;

  for(var I=0;i i ){

  a=I;

  }

  代码9:

  var a;

  for(var I=0;i ){

  a=I;

  }

  这四段代码在火狐浏览器下6和8的性能接近,7和9的性能接近,而6, 8 7, 9;

  最后我们来看一下空循环

  代码10:

  for(var I=0;我我){ }

  代码11:

  var I;

  while(I 100){ I;}

  最后的测试出现了神奇的结果,火狐下代码10所花的时间与代码11所花的大约是24:1。所以它不具备参考价值,于是我没有放在一开始给大家看。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: