Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / JScript.NET

JavaScript Performance Tips - Part 2

5.00/5 (3 votes)
20 Sep 2013CPOL3 min read 15.2K  
JavaScript performance tips - Part 2

Introduction

Continuing from where I left last time, let's delve a bit deeper into performance aspects of JavaScript. While Part 1 was about basics, this section explores certain memory management techniques in JavaScript. So before you proceed, please refresh your memory on prototype and its internals.  

Background

This tip assumes some basic knowledge of prototype and some internals on how functions work in JavaScript. Readers can read this tip independent of Part 1

Tips on Performance

  1. The problem with functions inside functions:
    JavaScript
    function Person(fname,lname) {
        this.firstName = fname;
        this.lastName = lname;
     
        this.getName = function(){
            return this.firstName + ' ' + this.lastName;
        }
     
    }
    //lets say you are doing something like this in your code
    var p1 = new Person("Jack", "Smith");
    var p2 = new Person("John", "Doe");

    Everytime you create a new person, JS Engine allocates memory for firstName, lastName and getName. I don't mean to say that this is wrong but this is inefficient. Isn't it? So, what's the solution? Move getName to prototype!

  2. Move common functions to prototype:
    JavaScript
    //Better
    Person.prototype = {
       getName : function(){
           return this.firstName + ' ' + this.lastName;
       }
    }

    Once we move the getName method to prototype, you will observe that p1 and p2 will just hold a reference to the single memory block allocated for getName. How will this help? Well, if your app is creating many Person objects on the fly, less memory is allocated by browser when creating new Persons and hence the Garbage collector which kicks in intermittently in the app life cycle will quickly do its job and move on improving your app's user experience by reducing the flicker.

  3. Array memory management:
    JavaScript
    function foo() {
        var arr = [];
        ....
        arr.push(1);
        ....
        //May be now you want to clean up the array!
        arr = [];
        arr.push(2);
        ....
    }

    What's wrong with the above code? The function foo simply creates an array, pushes an item and then somewhere down the line cleans up the array and pushes another item. Well, first looks can be deceiving at times! Observe closely that second time, the array is recreated. So effectively, JS Engine requests for another memory block and the browser allocates one. The older memory block is awaiting garbage collection. Hmm... is it necessary to recreate an array? Well, the intention was to just clean up not allocate a new array. So, what's the solution?

    JavaScript
    //lets try the cleanup differently!
    arr.length = 0;
    

    Observe that if you replace the above statement with the cleanup statement in foo, you still get the same result! The difference is that no new memory block is allocated by the browser in this case.

  4. Keep private methods outside the plugin's return.
    JavaScript
    (function($){
       $.fn.pluginName = function(config){
          return this.each(function(){
             //...
             function doSomething(){};
          });
       }
    })(jQuery);
     
    $(".myClass").pluginName({o:1});

    The problem with the above jQuery plugin is that the function doSomeThing is created for each iteration of the selector. So if your jQuery selector returns 10 DOM elements which have a CSS class called 'myClass', your plugin is consuming lot of memory by requesting the engine to allocate 10 blocks for doSomething. How can we avoid this? Well, simply move your private function outside of this.each iteration!

    JavaScript
    //This is cleaner and efficient
    (function($){
       $.fn.pluginName = function(config){
          return this.each(function(){
             //....
             myPrivates.doSomething();
          });
          var myPrivates = {
            doSomething : function(){};
          };
       }
    })(jQuery);
     
    $(".myClass").pluginName({o:1});

    You don't necessarily have to create a private object, just moving out doSomething out of the iterator is good enough!

  5. Avoid anonymous functions inside setTimeout or setInterval:
    JavaScript
    setTimeout(function(){
      //do Something
    }, 2000);
    

    What's wrong with the above code? You should have guessed it by now if you got the theme of this article. Smile :-| Yes, the JS Engine simply creates a new anonymous function every 2 seconds! More garbage and you know the consequence! The solution is obviously to use a named function and reference it inside setTimeout.

    JavaScript
    //Much better
    function myCallback(){
      //do Something
    };
    setTimeout(myCallback, 2000);
    
  6. See if you can get away by using Static classes in your app. Use instance classes only when necessary. The idea is to use memory sparingly - only when it's an absolute necessity.
    JavaScript
      //Simpler and better
       var MyApp = MyApp || {};
       MyApp = (function () {
        var doSomething = function() { }
        return {
            init: function (a) {
                
            };
        };
    })();
    MyApp.init();

Parting Note

The improvements listed above are common pitfalls which can be avoided in our day to day coding. I hope you find these tips useful. If yes, please share it with the developer community.

Happy learning. Smile :-|

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)