jQuery DOM Manipulation und Performance

February 10th, 2010

I’m not promising this blog is gonna be hot and spicy all the time, but It’s been a while since I posted, and I thought I would make it something geeky — performance tests! I swear I’m working on a new template for this site, and naturally it’s going to revolutionize web design. Unfortunately, skiing and learning to play the Ukulele keeps eating up all my time! But I digress…

Flame war! (Intro)

I was actually a sociology major in college, so I kind of enjoy the rigor of trying to test things well. This is not a rigorous test — but I did learn some fun stuff!

Over at NETTUTS there was a discussion about the best way to update the DOM using jQuery. The author suggested this method, and was promptly called an idiot:

var updatedText = "Value1
Value2";
$("#container").html(updatedText);

I actually used a variation on this method when writing dmMonocle, my jQuery plugin which makes viewing images within library digital collections, such as the Southern Nevada Boomtowns Collection, a bit easier. What dmMonocle does is generate a series of tiles (divs) and then injects them all together at once, just as the author suggested above. Others claimed that the built-in jQuery methods (.html() & .append()) were more readable, and should therefore be used.

Test me once, shame on you (Methods)

In these cases, I like to let the numbers speak for themselves, and so I created a series of tests using JSFiddle that test the performance of three methods. I posted a couple of simple tests to NETTUTS this morning, but I thought it would be fun to get more in-depth and play around with loops of console profiles and timers to test performance (you know, how every sane person likes to spend their time)!

I wanted to time and profile three different functions:

  • Build a string of spans and inject it once into a container using the .html() method
  • Update each one of the spans individually with $(#span).html("new html")
  • Building the spans within the contain using the .appendTo() method.

As the bad joke of a subheading should tell you, we don’t simply want to run these timers and profiles once, we want to run them 100 times (more would probably be better). To run them once would be a grave mistake. Don’t you remember doing 10 trial runs in science class to eliminate error? Did you think the cheeky lab report workflow of this post was a mistake?

I’m also running these tests on a Summer 2009 Macbook Pro, and would love to hear about results from other machines.

Show me the code! (Data)

As I said, these tests run each method 100 times. Scratch that, Firefox ate it when I tried that =P I’ll just run em a bunch manually and record numbers the good ol’ fashioned way. I’ll work on best practices for averaging results in a future post

Chrome

My new browser of choice:

  1. First Test Average: 2-3ms
  2. Second Test Average: 6-8ms
  3. Third Test Average: 8-10ms

Firefox 3.6

Tried and true (but slooooooow):

  1. First Test Average: 11-12ms
  2. Second Test Average: 21-23ms
  3. Third Test Average: 37-39ms

I mean look at that. 3-5x slower than Chrome 4 on simple operations.

Safari

Safari was… creepy with how consistent it was. I think I may be doing something wrong

  1. First Test Average: 3ms
  2. Second Test Average: 6ms
  3. Third Test Average: 16ms

Internet Explorer

I can only run IE on a virtual machine at the moment, and I’m not sure how reliable that is. Give me some data!

Blah Blah Blah, what’s the bottom line (Results und Discussion)

Bottom line is that, according to my tests, using native JavaScript strings to build the html and injecting it once is roughly twice as fast as the updating method, and 3-5x times faster than append method (which is the most similar to the original string function). These results are due to the fact that the string method skips over calling not only the jQuery constructor $() on each iteration, but also the jQuery methods .html() and .append(), which themselves call multiple functions (as demonstrated by the profiling tests).

Based on those facts, when I need to inject any significant amount of code, I’m going to try to do as much building as I can in regular old JavaScript, avoiding the DOM and unnecessary jQuery methods as much as possible. Look, jQuery is great and really fast; I mean, I’m literally talking about 2-5x slower than 2 miliseconds). But, I’ll basically take any speed advantage I can get, and in this instance there is a clear winner. I personally don’t think the JavaScript is too much uglier or less maintainable than the jQuery fashion, but that is really a matter of taste. When it comes to the data, there’s no debate.