• 【翻译】优化JavaScript代码的几点建议


       客户端脚本能够使得应用更加具有吸引力,但是浏览器对脚本代码的解释执行可能也会导致效率低下。

       这里我们探讨几个优化JavaScript代码的最佳实践建议。

    1、处理字符串

          字符串拼接在IE 6、7下的垃圾回收性能很差。虽然IE 8已经解决了这个问题。如果你的用户中有相当一部分人使用IE 6、7,那么你得谨慎构建你的字符串了。     

          比如这个例子:

    var veryLongMessage =
    'This is a long string that due to our strict line length limit of' +
    maxCharsPerLine +
    ' characters per line must be wrapped. ' +
    percentWhoDislike +
    '% of engineers dislike this rule. The line length limit is for ' +
    ' style purposes, but we don't want it to have a performance impact.' +
    ' So the question is how should we do the wrapping?';

          不要直接使用字符串拼接 + ,更好的做法是用join:

    var veryLongMessage =
    ['This is a long string that due to our strict line length limit of',
    maxCharsPerLine,
    ' characters per line must be wrapped. ',
    percentWhoDislike,
    '% of engineers dislike this rule. The line length limit is for ',
    ' style purposes, but we don't want it to have a performance impact.',
    ' So the question is how should we do the wrapping?'
    ].join();

          类似的,在条件分支语句或循环语句中使用字符串拼接也很低效。不好的做法:

    var fibonacciStr = 'First 20 Fibonacci Numbers
    ';
    for (var i = 0; i < 20; i++) {
    fibonacciStr += i + ' = ' + fibonacci(i) + '
    ';
    }

          正确的做法:

    var strBuilder = ['First 20 fibonacci numbers:'];
    for (var i = 0; i < 20; i++) {
      strBuilder.push(i, ' = ', fibonacci(i));
    }
    var fibonacciStr = strBuilder.join('');
     

    2、使用helper functions构建字符串片段

          通过将string builder传入helper function来避免临时存储消耗。

          例如不该用下面这种:

    var strBuilder = [];
    for (var i = 0, length = menuItems.length; i < length; i++) {
      strBuilder.push(this.buildMenuItemHtml_(menuItems[i]));
    }
    var menuHtml = strBuilder.join();

          而应该使用:

    var strBuilder = [];
    for (var i = 0, length = menuItems.length; i < length; i++) {
      this.buildMenuItem_(menuItems[i], strBuilder);
    }
    var menuHtml = strBuilder.join();

    3、定义类方法

         下面的代码是低效的,因为每次有一个baz.Bar实例被创建,一个新的函数和闭包就为foo创建:

    baz.Bar = function() {
      // constructor body
      this.foo = function() {
      // method body
      };
    }

           更优的做法是:

    baz.Bar = function() {
      // constructor body
    };
    baz.Bar.prototype.foo = function() {
      // method body
    };

           通过这种方法,不管有多少个baz.Bar实例被创建,只有一个function被创建,并且也不形成闭包。

     

    4、初始化实例变量

          将实例变量的声明/初始化放到prototype中,如果实例变量带有一个值类型的初始值(即number、Boolean、null、undefined或字符串类型值)。这避免了每次构造器创建时都运行毫无意义的初始化代码。

          不好的做法:

    foo.Bar = function() {
      this.prop1_ = 4;
      this.prop2_ = true;
      this.prop3_ = [];
      this.prop4_ = 'blah';
    };

          更优的做法:

    foo.Bar = function() {
      this.prop3_ = [];
    };
    foo.Bar.prototype.prop1_ = 4;
    foo.Bar.prototype.prop2_ = true;
    foo.Bar.prototype.prop4_ = 'blah';

    5、避免闭包中的陷阱

          闭包是一个强大有用的东西。但是他们有一些缺点,包括:

    1、他们是内存泄露的最主要元凶
    2、创建一个闭包比创建一个内联函数慢,比重用一个静态函数更慢。

          比如:

    function setupAlertTimeout() {
      var msg = 'Message to alert';
      window.setTimeout(function() { alert(msg); }, 100);
    }

          比下面的代码更慢:

    function setupAlertTimeout() {
      window.setTimeout(function() {
        var msg = 'Message to alert';
        alert(msg);
      }, 100);
    }

          上面的代码又比下面的代码更慢:

    function alertMsg() {
      var msg = 'Message to alert';
      alert(msg);
    }
    
    function setupAlertTimeout() {
      window.setTimeout(alertMsg, 100);
    }

          闭包增加了一层作用域链。当浏览器解析属性时,每一层的作用域链都必须被检查。在下面的例子:

    var a = 'a';
    function createFunctionWithClosure() {
      var b = 'b';
      return function () {
        var c = 'c';
        a;
        b;
        c;
      };
    }var f = createFunctionWithClosure();
    f();

           当f被调用时,引用a比引用b更慢,引用b又比引用c更慢。

           查看IE+JScript Performance Recommendations Part 3: JavaScript Code inefficiencies 来获取更多在IE下正确使用闭包的信息

    6、避免with

          避免在代码中使用with语句。它对性能产生负面影响,因为它改变了作用域链,使得在其它作用域中查找变量的代价更加昂贵。

    7、避免浏览器内存泄露

          内存泄露是web应用中的常见问题,会导致巨大的性能问题。当浏览器消耗的内存增加,你的其他Web应用以及用户系统的其他程序都会变得很慢。最常见的内存泄露场景是JavaScript引擎和浏览器的DOM对象的循环依赖,比如下面这个例子:

    <script language='javascript'>
       var menu = document.getElementById('myMenu');
       AttachEvent(menu);
       function AttachEvent(element) {
          element.attachEvent( "onmouseover", mouseHandler);
          function mouseHandler(){ /* whatever */ }
       }
    </script>
           又比如下面的代码:
    var myGlobalObject;
    
    function SetupLeak(){
       //Here a reference created from the JS World 
        //to the DOM world.
        myGlobalObject=document.getElementById("LeakedDiv");
    
        //Here DOM refers back to JS World; 
        //hence a circular reference.
        //The memory will leak if not handled properly.
        document.getElementById("LeakedDiv").expandoProperty = myGlobalObject;
    }
           更多信息可以参考:http://www.javascriptkit.com/javatutors/closuresleak/index.shtml
  • 相关阅读:
    Spring温故而知新 – bean的装配
    Lambda表达式和表达式树
    委托的内部机制
    委托(C#)
    linux wdcp安装
    linux各个文件夹作用
    linux基本命令
    python调用html内的js方法
    Win10在右键菜单添加“在此处打开命令窗口”设置项
    python read文件的r和rb的区别
  • 原文地址:https://www.cnblogs.com/feichexia/p/2840806.html
Copyright © 2020-2023  润新知