A Couple of Quick Tips for JavaScript Optimization

Posted: April 27, 2009 Comments(3)

I’m a huge fan of JavaScript. I’ve spent the past couple years trying to really enhance my knowledge of the subject, and with the volatile ingenuity of the modern Web, I’m able to pick up new things on a very consistent basis. Keeping myself in check, however, is a recognition that I’ll never embrace all there is to know about JavaScript. The best I can do is teach myself everything I can, and have consistent discussion with those who know more than me. What better way than publishing?

I work primarily in jQuery when I write JavaScript. I’ve become very comfortable with the library, as it meets my needs on a very consistent basis. I’m not biased, however. With each project, I evaluate whether there’s a need for a full library such as jQuery. There have been many projects which simply didn’t need the full functionality of a library as feature-rich, and therefore bigger in file size, as jQuery. Many times I’ll use a more lightweight library such as DOMAssistant which lets you build your own library with modules you’ll be working with. There have been many times where dLite (DOMAssistant Lite) has been more than enough to work with, this site for example.

You should evaluate which library you’re using on a case-by-case basis as well, as it seems that with jQuery being so popular, many designers simply default to using it with every project, even if they’re only binding a click event in one area of a website.

As I’ve been writing more elaborate pieces of JavaScript, I’ve picked up a bit more knowledge in optimizations. It’s become my focus lately; trying to write cleaner JavaScript resulting in faster processing and therefore a better experience for the user. I’d like to quickly discuss a couple things I’ve started doing to ease the load of JavaScript on the browser and therefore the user.

Creating reference variables

Traversing the DOM is sometimes expensive, depending on your selector. Keeping node selection to a minimum will help speed up your scripts quite a bit. If you’re working with a specific node repeatedly, it will probably be in your best judgement to define a variable with that node, instead of traversing for it repeatedly.

For example, if you need to manipulate multiple children of a parent element, it is probably in your best interest to define the parent element as a variable, and work with the children from there.

While not a gigantic enhancement, we can project the benefits on a larger scale, especially when working with a classed element as opposed to one which has an id. This comes in especially handy if you’re nesting animations, and you need to work with the initial element throughout the process. You can simply reference the variable you’ve defined instead of possibly having to hunt for a parent() or two.

While libraries such as Sizzle are dramatically enhancing node selection, it’s always good practice to write inexpensive code, and sometimes selector abstraction is the way to go.

Avoiding iterative DOM manipulation

Perhaps the biggest change to embrace was to avoid manipulating the DOM iteratively. That is to say, making a change to the DOM each time you run through a loop. This practice is definitely not limited to jQuery, but I’ll be using jQuery syntax in code samples throughout this article.

Keeping this in mind came in very handy as I was working with creating custom selects via jQuery. Essentially what I needed to do was loop through an existing select and duplicate each option value as a list item in a newly created list. At first you may write your snippet like so:

// parse all options within the select and set indices
var i = 0;
targetselect.find('option').each(function() 
{
  // add the option
  target.find('.options ul').append('<li><a href="#"><span class="value">' + $(this).text() + '</span><span class="hidden index">' + i + '</span></a></li>');

  // check to see if this is what the default should be
  if($(this).attr('selected') == true)
  {
    targetselect.parent().find('a.dropdown_toggle').append('<span></span>').find('span').text($(this).text());
  }
  i++;
});

You’ll notice that with each iteration of the loop, we’re appending a list element to our unordered list. If you’re running this function on a document with quite a few selects (especially with many options), you’ll notice quite a bit of lag.

This code can be better optimized by abstracting the injection until after processing the select in its entirety by concatenating the list items to a string, and then appending that string a single time:

// parse all options within the select and set indices
var i = 0;
var options = '';
targetselect.find('option').each(function() 
{
  // add the option
  options += '<li><a href="#"><span class="value">' + $(this).text() + '</span><span class="hidden index">' + i + '</span></a></li>';

  // check to see if this is what the default should be
  if($(this).attr('selected') == true)
  {
    targetselect.parent().find('a.dropdown_toggle').append('<span></span>').find('span').text($(this).text());
  }
  i++;
});
target.find('.options ul').append(options);

Instead of appending the list item with each iteration, which becomes very expensive very quickly, we simply build a string and work with it once the heavy lifting has been done.

Do you have any tips?

I know these tips are nothing extraordinary, but I hope they may help you enhance the performance of your future scripts. I realize that my code examples use jQuery syntax, the tips themselves can be applied to any implementation of JavaScript.

Do you have any techniques you’re using consistently in the interest of both code organization as well as optimization?

Get my newsletter

Receive periodic updates right in the mail!
  • This field is for validation purposes and should be left unchanged.

Comments

  1. Very informative article. I really liked it.

    I hate to admit it, but with some of the work I have definitely been guilty of just going the easy route with jQuery when it potentially wasn’t necessary.

  2. @Jesse Altman: I’m glad you liked it! Believe me when I say you’re not the only one who usually defaults to jQuery — I’m tempted to do just that with each and every project. It’s not any sort of crime, though, as jQuery prides itself on being quite lightweight as it stands. jQuery is a great solution, as are many JavaScript libraries, but there are sometimes those cases where all you need to do is hook an event or two. Thanks for stopping by!

  3. I’ve found that when iterating a large number of elements using the reverse do while loop actually does speed things up.

    Also, if you’re working on a really script heavy page (for example one that does a lot of initialization when the dom is ready) separating chunks into functions and calling them with slight delays can make a big difference in perceived performance of the page. For example

    init1
    setTimeout(init2,100)
    setTimeout(init3,250)

Leave a Reply

Your email address will not be published. Required fields are marked *