Generating a grid (table) view from the results of an Ajax call is a common Web 2.0 use case. But performance can be an issue, especially on IE7.

Let's look at an example without the actual Ajax part; just generating a table and inserting it into the DOM. Here is a naive implementation:


 <script src="prototype.js" type="text/javascript"></script>

 <SCRIPT>

 var MAX_ROWS = 500;
 var MAX_COLS = 20;

 function populate() {

     var tableDom = new Element("table");
     var tableBodyDom = new Element("tbody");

     for (var row = 0; row < MAX_ROWS; row++) {
        var rowDom = new Element("tr");
        for (var col = 0; col < MAX_COLS; col++) {
            var colDom = new Element("td");
            colDom.innerHTML = row + ":" + col;
            rowDom.appendChild(colDom);
        }
        tableBodyDom.appendChild(rowDom);
     }

     tableDom.appendChild(tableBodyDom);
     $("grid").appendChild(tableDom);
 }

 function populateTimer() {

    var start = new Date().getTime();
    populate();
    $("info").update(new Date().getTime() - start + "ms");
 }

 Event.observe(window, "load", populateTimer);

 </SCRIPT>

 <DIV id="info">
 </DIV>

 <DIV id="grid">
 </DIV>

Results:
  • Firefox - 1660ms
  • Chrome - 446ms
  • IE7 - 6906ms

Constructing the table with via the DOM is fairly slow, especially on IE. This is well documented at quirksmode. So, let's try an innerHTML implementation:


 function populate() {

     var tableHtmlArr = ["<TABLE>"];
     for (var row = 0; row < MAX_ROWS; row++) {
         tableHtmlArr.push("<TR>");
         for (var col = 0; col < MAX_COLS; col++)
             tableHtmlArr.push("<TD>" + row + ":" + col + "</TD>");
         tableHtmlArr.push("</TR>");
     }
     tableHtmlArr.push("</TABLE>");
     $("grid").innerHTML = tableHtmlArr.join("");
 }

Results:
  • Firefox - 315ms
  • Chrome - 108ms
  • IE7 - 360ms

So far so good. IE7 is actually pretty fast at concatenating all this HTML and displaying it. IE8beta2 is even better. So, why is this post titled "Ajax grid performance in IE"?

Let's try one more test. What if we insert more layout elements into the grid? In this implementation, I have just wrapped each cell in five nested DIVs. (This is an extreme example, but it's not hard to imagine some rich formatting in those cells.)


          for (var col = 0; col < MAX_COLS; col++)
              tableHtmlArr.push("<TD><DIV></DIV></DIV></DIV></DIV>" + row + ":" + col + "</DIV></DIV></DIV></DIV></DIV></TD>");

Results:
  • Firefox - 540ms
  • Chrome - 272ms
  • IE7 - 2734ms

As you can see, the performance in IE7 degrades dramatically as the complexity of the HTML increases. If you put a timer before the innerHTML setter, you will see that the time increase to that point is negligible. It's actually not a javascript performance problem at all; it's DOM insertion performance!

The IE8 team has actually blogged about this. They estimate that fully 70% of the browser cycles are dedicated to either "Layout" or "Rendering" on real world applications.

Even worse, it's not getting better on IE8. This test actually gets slower on IE8beta2. My hypothesis is that all the work they are doing to increase their Acid2 score (while maintaining a backwards compatibility mode) is actually slowing down their rendering performance.