Optimizing jQuery – 10 Ways to Write Better Code

December 29th, 2011 Leave a comment
Like the article?
Optimize your jQuery - 10 Ways to Write Better Code

Most of us that began writing jQuery started because we heard how awesome it was and we were frustrated at JavaScript. jQuery is awesome, but like any programming language, there can be problems and pitfalls we want to try to avoid. This article talks about ten common better uses of jQuery that will help you get your job done right. They won’t make you a jQuery expert, but they will show you some best practices and better ways of using the library.

1. Make Sure Your Version is Up-to-date

Why: jQuery is constantly changing and updating. Improvements to the efficiency of the code are being added that can improve performance. Keeping your jQuery version up to date can prevent bugs and other problems that have already been fixed in newer versions.

Another alternative to this is to load the framework from Google, instead of hosting the jQuery library yourself. Google Code hosts all of the different versions of jQuery and you shouldn’t notice a difference is load time since Google Code is pretty fast. You will also get the advantage of the library being cached on the user’s system if they have recently visited another site that uses jQuery hosted on Google. There are two different ways you can do this:

A direct reference to the file:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>  

Or use the API from Google to load it:

<script src="http://www.google.com/jsapi"></script>   
<script type="text/javascript">  
    // Load jQuery   
    google.load("jquery", "1.7.1");

    google.setOnLoadCallback(function() {
        // Your code goes here.   
    });
</script>

2. Use Cached Variables Instead of Selector Calls

Many times we want to change several attributes of a selector and we do something like this:

$('p.welcome').css('color', '#FFFFFF');
$('p.welcome').text('Welcome');
$('p.welcome').addClass('paragraph');
$('p.welcome').fadeTo(1000, 1);

Doing this can really slow down your jQuery script performance since the script has to look up the selector each time to make all of these changes. If you switch to a variable instead, you can make all of these changes faster:

var $sel = $('p.welcome');
$wel.css('color', '#FFFFFF');
$wel.text('Welcome');
$wel.addClass('paragraph');
$wel.fadeTo(1000, 1);

This way, jQuery will cache the variable and it will be available for quick reuse instead of having to look up the selector again and again.

3. Limit DOM Manipulation

DOM manipulation and insertion options are costly and can begin to degrade the performance of your application significantly if overused. Try to avoid using .append(), .prepend(), .after() and .wrap() when there are other ways the problem could be solved. Here is an example:

var myList = $('#myList');

for (i = 0; i < 1000; i++) {
	myList.append(i);
}

The use of .append() slows down this simple operation to 216 milliseconds (on my PC), which may not seem like much but this again, is a simple example. To speed up the performance, you can build the list items as a string and then use HTML method to insert it. For example:

var myList = $('#myList');
var listItems = '';

for (i = 0; i < 1000; i++) {
	listItems += '<li>' + i + '</li>';
}

myList.html(listItems);

This presents a different solution that should yield the same results, however, this approach only takes 185 milliseconds, shaving 31 milliseconds off the time. Think about how much time you could be saving on your scripts in a real-world situation by just re-writing the solution.

4. Start Using Event Delegation

Event delegation is a way to avoid binding an event listener more than once. Since events that occur on an element are propagated out to all of its ancestors, an event listener can bind to only one ancestor and be in control of numerous elements instead of being bound to all of the elements individually.

Here is an example. Imagine you have the following HTML:

<ul class="myList">
	<li class="red">First Item</li>
	<li class="green">Second Item</li>
	<li class="yellow">Third Item</li>
	<li class="blue">Fourth Item</li>
</ul>
<p>Class of the last clicked item: <span id="last"></span></p>

If we wanted to display the class of the last item clicked in the “last” span, usually we would set up an event listener in jQuery that would look like this:

$("li").click(function(event) {
	$("#last").text(event.target.className);
});

When an <li> element is clicked, this event handler will insert the class name of the <li> into the text of the “last” ID. The unfortunate part of this code is that we now have an event listener that has to watch for all <li> tags. Essentially, it attaches itself to all <li> tags and becomes less efficient.

Delegation provides us a more efficient method of handling this:

$("ul").click(function(event) {
	if (event.target.nodeName == "LI") {
		$("#last").text(event.target.className);
	}
});

The main advantages here are that we have a single event listener for all of the <li> tags since the event listener of a <ul> tag will be propagated down to its ancestors and any new elements that we should add in later would have the same behavior, due to this inheritance. Now we not only have cleaner jQuery code, but we have a faster responding event listener.

5. Use Support to Check Browser Compatibility

Since jQuery is so good about cross-browser compatibility we rarely ever need to check which browser we are running in. However, it is good practice to use feature-detection instead of determining the browser as a more efficient way of ensuring compatibility. The built-in support functions of jQuery give us a way to check for features.

//Does this browser support opacity?
var opacity = $.support.opacity;

//Does this browser support the Box Model?
var boxModel = $.support.boxModel;

6. Combine and Minify

Today, most browsers do not yet have the capability to load multiple plug-ins and scripts simultaneously. The purpose of the minification process was to preserve the code while compressing it to a smaller file size that would be easier for the browser to handle. To speed up your script performance you should put them all into a single file and then compress (or minify) them so that they have faster load times.

There are several compression tools available to help you minify your scripts such as:

7. Use IDs instead of Classes

Since jQuery makes it seem just as easy to get a class as it does an ID, it is tempting to want to use classes more since they are a little more flexible. However, it is much better to use ID over class since jQuery uses the browser’s native getElementByID() to retrieve ID objects, which results in a faster query over classes that must be looked up using the DOM. This one can really create a significant difference. For example, using the code from #3:

var myList = $('#myList');
var listItems = '';

for (i = 0; i < 1000; i++) {
	listItems += '<li class="listItem' + i + '">List Item</li>';
}

myList.html(listItems);

for (i = 0; i < 1000; i++) {
	var selectedItem = $('.listItem' + i);
}

I made some modifications to the code. Now as each list item is created it gets the class listItem and I added a for loop to the end of the code that selects each item once. When run, this script can cause the browser to hang and it clocks at 5066 milliseconds, or just over 5 seconds. Wow! So what if we use ID?

var myList = $('#myList');
var listItems = '';

for (i = 0; i < 1000; i++) {
	listItems += '<li id="listItem' + i + '">List Item</li>';
}

myList.html(listItems);

for (i = 0; i < 1000; i++) {
	var selectedItem = $('#listItem' + i);
}

This script only takes 61 milliseconds to execute, making the ID over class nearly 100 times faster. That is a severe amount of optimization with only a little change.

8. Use for Instead of each

As we have seen in some previous examples, the use of native functions are always going to be faster than any others. Using a for loop to move through an array of values is going to take less time than using .each() to perform the same operation.

var array = new Array();

for (i = 0; i < 1000; i++) {
	array[i] = i;
}

This simple for statement takes about 2 milliseconds to complete. Which is probably what you would expect. The problem comes when we do things like this:

var array = new Array();

$.each(array, function(i) {
	array[i] = i;
});

Essentially we are performing the same task but in this case we are doing it a full 20 milliseconds slower. jQuery’s .each() method takes almost 10 times as long as the browser’s native for.

9. Use jQuery’s Internal Method to Store State

Many developers have learned that the most basic way to store state is with CSS. In the following example we have an expanding menu where we will toggle the menu up and down using the slideDown() and slideUp() based on its current state. First the HTML:

<div class="menuItem expanded">
    <div class="button">
        click me
    </div> 
    <div class="panel">
        <ul>
            <li>Menu item 1</li>   
            <li>Menu item 2</li>   
            <li>Menu item 3</li>   
        </ul>
    </div>
</div>

Next the script that provides the click event handler for the menu and performs the appropriate slide.

$('.button').click(function() {
	var menuItem = $(this).parent();
	var panel = menuItem.find('.panel');   
   
	if (menuItem.hasClass("expanded")) {   
		menuItem.removeClass('expanded').addClass('collapsed');   
		panel.slideUp();   
	} else if (menuItem.hasClass("collapsed")) {   
		menuItem.removeClass('collapsed').addClass('expanded');   
		panel.slideDown();   
	}
});

Pretty simple, right? If the menu is down, we use slideUp() if the menu is up, we use slideDown(). At this point many developers would add extra classes to store information about the HTML so that the state of the menu could be saved. However, there is a better way to go about this. jQuery has a built in method, data() that can be used to store the state of information in key/value pairs against any DOM element. So let’s change the above example to use the data() function instead of the “expanded” class.

$('.button').click(function() {   
	var menuItem = $(this).parent();
	var panel = menuItem.find('.panel');   
   
	if (menuItem.data('collapsed')) {   
		menuItem.data('collapsed', false);   
		panel.slideDown();     
	} else {   
		menuItem.data('collapsed', true);   
		panel.slideUp();   
	}
});

This creates a cleaner solution to the problem than a bunch of CSS classes. There is also a removeData() method that you can check out here: http://api.jquery.com/jQuery.removeData/.

10. Speed Up Your Page for SEO

For all of the coders that have to worry about SEO and how their page is seen by search engine spiders, this last tip is for you. We can speed up our page loads and clean up the HTML for search spiders using a “lazy load” process. This process involves loading whole chunks of the page using AJAX after the main bulk of the page has been loaded. This way the user can begin using the page and spiders can start indexing. The trade-off here is that you are making extra requests to your server when pages are requested and parts of your page may not be immediately available. However, faster load times can create a better search engine score so you may be able to reap the benefits without too many problems.

The trick to this is to put all of your HTML into a static page and then use the jQuery .load() method to pull it in once the DOM is ready. Here is an example:

$('#forms').load('content/myDocument.html', function() {   
    // Code here runs once the content has loaded   
    // Put all your event handlers etc. here.               
});

I hope you have enjoyed this article on how to improve your jQuery code. There are many changes that you can start making to your code immediately and some tricks that you can keep up your sleeve for when you run into problems. Remember that the best thing you can do is to keep learning and you will get to the point where you do these things as second nature and not fall into bad habits that create bad code.

Help us spread the word!
  • Twitter
  • Facebook
  • LinkedIn
  • Pinterest
  • Delicious
  • DZone
  • Reddit
  • Sphinn
  • StumbleUpon
  • Google Plus
  • RSS
  • Email
  • Print
Don't miss another post! Receive updates via email!

Comment