Javascript Performance Optimizations

Josh Powell

Subscribe to Josh Powell: eMailAlertsEmail Alerts
Get Josh Powell: homepageHomepage mobileMobile rssRSS facebookFacebook twitterTwitter linkedinLinkedIn


Web 2.0 : Tutorial

Using jQuery's Append Method Correctly

The difference between poorly written, slow code and tight, fast code.

The .append() method is perhaps the most misused of all jQuery methods. While an extremely useful and easy method to work with, it dramatically affects the performance of your page. When misused, the .append() method can cripple your JavaScript code's performance. When used well, it'll keep your script humming along.

Here is a typical example of append misuse:

JavaScript:
  1. var arr = reallyLongArray;
  2. $.each(arr, function(count, item) {
  3. var newTd = $('<td></td>').html(item).attr('name','pieTD');
  4. var newTr = $('<tr></tr>');
  5. newTr.append(newTd);
  6. $('table').append(newTr);
  7. });

Ran Once: Profile (308.697ms, 17861 calls, Firefox 3.06)
Ran in a for loop 100 times: Profile (51782.295ms, 1805100 calls)

If you're coming from Prototype to jQuery, chances are this looks quite natural to you. It's the way that Prototype does node creation/insertion, but with a little bit of jQuery chaining thrown in. Let's see how we can improve this.

JavaScript:
  1. var arr = reallyLongArray;
  2. $.each(arr, function(count, item) {
  3. var newTr = '<tr><td name="pieTD">' + item + '</td></tr>';
  4. $('table').append(newTr);
  5. });

Ran Once: Profile (107.458ms, 3991 calls, Firefox 3.06)
Loop of 100: Profile (21641.336ms, 399100 calls)

Whoa! Nearly a 3x difference, and much simpler to look at. jQuery can take more then one node at a time and create them all at once. You also don't need to wrap it in $() before appending it. jQuery knows what to do. But wait, there's more!

JavaScript:
  1. var arr = reallyLongArray;
  2. var textToInsert = '';
  3. $.each(arr, function(count, item) {
  4. textToInsert  += '<tr><td name="pieTD">' + item + '</td></tr>';
  5. });
  6. $('table').append(textToInsert);

Ran Once: Profile (30.792ms, 778 calls, Firefox 3.06)
Loop of 100: Profile (8505.37ms, 77800 calls)

Taking full advantage of the ability of jQuery to insert a chunk of html in a string means only having to call insert once. It's much quicker, with an approximately 9-10x speed increase from the initial algorithm! This will be fast enough for 95% of cases, but for strings with lots of string concatenation… Wait, there's more!

JavaScript:
  1. var arr = reallyLongArray;
  2. var textToInsert = [];
  3. var i = 0;
  4. $.each(arr, function(count, item) {
  5. textToInsert[i++] = '<tr><td name="pieTD">';
  6. textToInsert[i++] = item;
  7. textToInsert[i++] = '</td></tr>';
  8. });
  9. $('table').append(textToInsert.join(''));

Credit for this one goes to Michael Geary
Ran Once: Profile (29.724ms, 778 calls, Firefox 3.06)
Loop of 100: Profile (8298.699ms, 77800 calls)

This version is a bit harder to understand, as the html is not in an easy to read format, and the results vary by browser* (see below for further analysis), but in most current and next generation browsers, adding to an array and joining it into a string at the end is quicker then doing string concatenations. So, if you are looping through a large number of string concatenation and need some more speed, you should consider this method. So, now we're done, right? This is as blazingly fast as we can get it? Not quite.

JavaScript:
  1. var arr = reallyLongArray;
  2. var textToInsert = [];
  3. var i = 0;
  4. var length = arr.length;
  5. for (var a = 0; a <length; a += 1) {
  6. textToInsert[i++] = '<tr><td name="pieTD">';
  7. textToInsert[i++] = arr[a];
  8. textToInsert[i++] = '</td> </tr>' ;
  9. }
  10. $('table').append(textToInsert.join(''));

Ran Once: Profile (29.72ms, 587 calls, Firefox 3.06)
Loop of 100: Profile (8274.359ms, 58700 calls)

As handy as .each() is for small loops, calling a function that executes a callback inside of a loop will always be slower than just creating the loop in pure JavaScript. The difference here isn't so noticeable because the array I used only has a length of 190, but for really large loops it makes a measurable difference. In addition, while the difference is very slight (.000062 vs .000037 ms over 1,000,000 empty loops), it is quicker to save the array length in a variable and use it instead of looking up an object property every loop (thanks Karl Swedberg!).

For most of your uses, the method of creating one really long string and appending it at the end will be the best choice, as it makes the best use of the trade offs of code legibility, ease of programming, and speed.

In addition, I just read up that appending a list of <tr>s with a <tbody> around them is significantly faster then appending the <tr>s without the <tbody>.

Google Groups JQuery thread here.

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.