Optimizing JavaScript code

Authors: Gregory Baker, Software Engineer on GMail & Erik Arvidsson, Software Engineer on Google Chrome

Recommended experience: Working knowledge of JavaScript

Client-side scripting can make your application dynamic and active, but the browser's interpretation of this code can itself introduce inefficiencies, and the performance of different constructs varies from client to client. Here we discuss a few tips and best practices to optimize your JavaScript code.

Defining class methods

The following is inefficient, as each time a instance of baz.Bar is constructed, a new function and closure is created for foo:

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

The preferred approach is:

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

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

With this approach, no matter how many instances of baz.Bar are constructed, only a single function is ever created for foo, and no closures are created.

Avoiding pitfalls with closures

Closures are a powerful and useful feature of JavaScript; however, they have several drawbacks, including:

  • They are the most common source of memory leaks.
  • Creating a closure is significantly slower than creating an inner function without a closure, and much slower than reusing a static function. For example:

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

    is slower than:

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

    which is slower than:

    function alertMsg() {
      var msg = 'Message to alert';
      alert(msg);
    }

    function setupAlertTimeout() {
      window.setTimeout(alertMsg, 100);
    }
  • They add a level to the scope chain. When the browser resolves properties, each level of the scope chain must be checked. In the following example:

    var a = 'a';

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

    var f = createFunctionWithClosure();
    f();

    when f is invoked, referencing a is slower than referencing b, which is slower than referencing c.

See IE+JScript Performance Recommendations Part 3: JavaScript Code inefficiencies for information on when to use closures with IE.

Avoiding with

Avoid using with in your code. It has a negative impact on performance, as it modifies the scope chain, making it more expensive to look up variables in other scopes.