RSS
 

Quick Tip – jQuery Newbs: Stop Jumping in the Pool

07 Oct

As editor of Nettuts+, I get to review a lot of code from tutorial submissions. Despite the fact that jQuery has been available for years now, there is still one frequent mistake that I see more than anything else.


Example #1

Consider the following bit of code:

$('.nav a').click(function() {
  $(this).hide();
  $(this).css('color', 'red');
  $(this).show();

  alert('something else');

  $(this).hide();

  return false;
});

The code above is overly complicated for a variety of reasons. Don’t worry over what the code actually does (it’s gibberish). Instead, I want you to look at all of those references to $(this).

Think of the DOM as a pool.

Think of the DOM as a pool. Remember when you were a kid, and would dive into the pool for coins, while your parents acted like they were watching? That will be our real-world comparision.

Every time you use $('.someClass'), jQuery jumps into the pool (DOM), and searches for that coin (or nodes). So, when you reference it multiple times within a function, that’s a lot of diving. Or, to cut the real-world comparison, it’s wasteful and unncessary. Why call upon jQuery if you don’t require it? You should perform what we call “caching.”

$('.nav a').click(function(e) {
   var anchor = $(this);

   anchor
      .hide()
     .css('color', 'red')
     .show();

   alert('something else');

   anchor.hide();

   e.preventDefault();

});

This is much cleaner. While modern browser engines are incredibly fast these days, and will make up for your poor coding as best as possible, you should still strive to write efficient code, and keep from wasting all that energy jumping in the pool. Now, technically, if you pass jQuery a DOM node, like this, it doesn’t re-query the DOM. It simply returns a jQuery object.

Just because the performance difference between the two will honestly be negligible, we write clean code for ourselves.

Example 2

Let’s consider a slightly more complicated example: tabs.

$('.tabs li').css('position', 'relative');

$('.tabs li').click(function() {
   $('.tabs li').removeClass('active');
   $(this).addClass('active');
   $(this).load('someHref', function() {} ); // example
   $(this).css('top', '1px');
});

This code is all over the place. It’s ugly, and inefficient. Fix number one is to get rid of all that CSS. You’d only place styling in your JavaScript if the values were created dynamically. For example, if you need to calculate the precise location an element should be on the screen, you could use .css('left', calculatedValue). In this case, it can all be exported to an external stylesheet. That leaves us with:

$('.tabs li').click(function() {
   $('.tabs li').removeClass('active');
   $(this).load('someHref', function() {} ); // example
   $(this).addClass('active');
});

Next, again, why do we keep querying the DOM for .tabs li and $(this)? Stop jumping in the pool. Let’s “cache” the location of .tabs li.

var tabs = $('.tabs li');

tabs.click(function() {
   tabs.removeClass('active');
   $(this).load('someHref', function() {} ); // example
   $(this).addClass('active');
});

Better, but we’re still calling $(this) twice, which isn’t a huge deal. But, from my experiences, if you don’t nip it in the bud early, this number quickly increases.

var tabs = $('.tabs li');

tabs.click(function() {
   var tab = $(this);
   tabs.removeClass('active');
   tab.addClass('active')
     .load('someHref', function() {} ); // example
});

Filtering

Another (slightly less optimized) option would be to use filtering.

var tabs = $('.tabs li');

tabs.click(function() {
   tabs.removeClass('active')
       .filter(this)
       .addClass('active')
       .load('someHref', function() {} ); // example
});

The difference in this case, is that, rather than referencing $(this), we’re using the filter() method to reduce the collection of list items down to only the one that was clicked.


What You Should Take Away

Yes, the world will not end if you reference $('.tabs) several times within a function. JavaScript engines are super fast these days. If you were to test the performance of doing so thousands of times, the difference in execution might be a couple hundred milliseconds. But still, the question remains: why would you?

Sometimes, when we use massive abstractions like jQuery, it’s easy forget that $('.tabs') is an actual function that runs a good bit of code. It should also be noted that these concepts apply to JavaScript in general – not just jQuery.

Use the caching techniques described above to write cleaner code…for yourself.

 
 

Tags: , ,