Surprising JavaScript rendering benchmark

I recently wrote about how I like to structure and render views in Backbone. Two of the most criteria when I write code are readability and performance. In JavaScript performance can be even more important because the range of devices your code runs on can vary dramatically.

I asserted that the single biggest performance hit in JavaScript rendering is accessing the DOM too much. I also said that worrying about optimizing things down to joining an array vs. creating elements via jQuery and document.createElement wasn’t worth it unless you’ve tested to see that’s the case.

I decided it’d be easy enough to write a few test cases to see what actually is the fastest. The use case tested was rendering a table with rows that contain different data. I created a quick benchmark with JsPerf. You can see the code and run it yourself here. There are four test cases:

  1. Baseline – a baseline case based on how I typically write Backbone views from the previous post.
  2. Add all elements to the DOM before rendering contents – a version to demonstrate the penalty of accessing the DOM too much. I was expecting this to be much slower.
  3. Render joining strings – A version where I don’t use jQuery to create elements, but instead just join strings together to create the HTML.
  4. Optimized render joining strings – This version is like #3, but I don’t use a child view, so I avoid creating view objects and calling additional methods. I was expecting this to be the fastest.

All test cases use Backbone models and views, but I set up the views and models beforehand, so only the different render implementations are benchmarked. For each test case, a <table> is rendered with a certain number of rows outputting names from Backbone models. The results are in iterations/s, so higher is better.

In total I did four runs. Two in Chrome 19 on my Mac and two in IE 7 on XP (couldn’t get an IE 6 box). For each browser, I did a run with 100 rows and another with 100o rows. The results are below.

Results: Surprisingly, the baseline version was the fastest in all cases. Being even faster than joining strings and setting the HTML is quite surprising. If anyone has ideas why, I’m very curious. Definitely will keep me from worrying about joining strings in the future.

Other interesting bits:

  • In IE, the other three test cases were all within the margin of error of each other. This makes sense for cases #3 and #4 (creating a new more objects and calling methods aren’t a huge performance hit), but it was surprising that the performance was  similar to adding table rows and cells to the DOM before modifying them.
  • In Chrome, it looks like there is something interesting going on between cases #3 and #4. Interestingly creating the TableRowView objects and using them to render rows is faster than doing it all in the TableView. Maybe some optimization the JS compiler is doing on the render method to make it faster?
Rendering 100 rows:

IE 7 / 100 rows

Rendering 1000 rows:

Chrome 19 / 1000 rows

IE 7 / 1000 rows