Web DevCenter
oreilly.comSafari Books Online.Conferences.
MySQL Conference and Expo April 14-17, 2008, Santa Clara, CA

Sponsored Developer Resources

Web Columns
Adobe GoLive
Essential JavaScript

Web Topics
All Articles
Scripting Languages

Atom 1.0 Feed RSS 1.0 Feed RSS 2.0 Feed

Learning Lab

PC Hardware in  Nutshell, 2nd Edition

Dynamic HTML Tables: Improving Performance

by Danny Goodman, author of JavaScript & DHTML Cookbook 05/06/2003

Sorting an HTML table's data instantly via a click on a column header has been possible ever since browsers allowed arbitrary page-content modification. With the wide browser adoption of the W3C Document Object Model (DOM) and other de facto standards, a developer has so many ways to re-populate a table, it may be hard to choose "the best" approach. I've recently investigated this issue in search of the most efficient techniques. Some of the findings took me by surprise.

Tables occupying one or two screens of page space perform acceptably well, regardless of the approach you use. But when a table might contain hundreds of rows (and you must display the entire table at once), it's important to squeeze every ounce of performance out of the table-modification code. The lessons learned from this exercise may shape the way you code all of your replaceable content.

Design Assumptions

The focus of my investigation was on the table content assembly and rendering processes -- how long it takes to populate a table's tbody section with dynamically generated content. The test scenario consisted of a partially prefabricated table structure with a fixed table header row and a modifiable tbody element where dynamic content would appear. The skeletal structure of the hard-wired HTML portion follows:

<div class="tableWrapper">
<table id="myTable">


   <tbody id="myTbody">

Dynamically generated test tables consisted of 500 rows, each row displaying five columns of data. Each td element was to have a class attribute assigned to it signifying its column position (col0 through col4), while tr element class names (tr0 and tr1) alternated between rows. Stylesheet assignments were kept simple:

<style type="text/css">
table {width:80%}
.tableWrapper {text-align:center}
.tr0 {background-color:#ffffcc}
.tr1 {background-color:#ccffcc}
.col0 {width:5%}
.col1 {width:50%}
.col2 {width:10%}
.col3 {width:25%}
.col4 {width:10%}

Raw data for the table was delivered to the browser as an embedded JavaScript array of objects. Each entry (object) in the array corresponded to one row of the table; values of each of the five object properties (named alpha through epsilon) corresponded to one table cell's data. Scripts created the array and objects while the page loaded so that acquisition and delivery of the data to the client was not a part of the performance measurement. Data sorting prior to content assembly was also intentionally kept out of the measurements. Both of my current O'Reilly books contain ample examples of array sorting that can be applied to sorting table contents.

Content Assembly

Related Reading

JavaScript & DHTML Cookbook
Solutions and Example for Web Programmers
By Danny Goodman

Next, I had to decide on the range of techniques to test in my goal of populating the tbody element with newly created rows and cells. From the browser compatibility standpoint, I should point out that modifying a segment of an existing table element is sadly broken in Internet Explorer for the Macintosh. I'll have more to say about a cross-browser workaround later in this article. Therefore, all of the following discussion applies to other mainstream, W3C DOM-capable browsers, such as Internet Explorer 6 for Windows, Mozilla-based browsers, Opera 7, and Apple's Safari (still in beta release as of this writing).

While scripters have several ways of accumulating table content, I focused on three broad categories:

  • Table-specific DOM methods.
  • Generic DOM node creation.
  • The non-standard, but largely supported notion of modifying a portion of a document's HTML as a string nested within an element (via the practically de facto standard innerHTML property).

Within these three major categories are numerous subcategories. The one I was particularly interested in was comparing the performance of creating table-cell content as DOM text nodes versus string innerHTML values of td element objects.

Approach I: Table-specific Methods

First introduced in Internet Explorer 4 for Windows, the tableElement.insertRow() and tableRowElement.insertCell() methods provide direct access to document-node tree elements to which you wish to add rows and cells. The methods are convenient because they automatically create new DOM element objects for you. The methods return references to the newly created rows or cells, making it easy for your scripts to assign property values to those new, but otherwise unpopulated, elements. Filling the content of each cell via its innerHTML property results in a fairly compact source code sequence inside of a repeat loop that draws data from an array of objects:

var tbodyElem = document.getElementById("myTbody");
var trElem, tdElem;
// loop through 500-item tableData array
for (var j = 0; j < tableData.length; j++) {
   trElem = tbodyElem.insertRow(tbodyElem.rows.length);
   trElem.className = "tr" + (j%2);
   // first column
   tdElem = trElem.insertCell(trElem.cells.length);
   tdElem.className = "col0";
   tdElem.innerHTML = tableData[j].alpha;
   // last column
   tdElem = trElem.insertCell(trElem.cells.length);
   tdElem.className = "col4";
   tdElem.innerHTML = tableData[j].epsilon;

If you prefer to stay within the bounds of pure W3C DOM compatibility, the innerHTML property would be off-limits. Instead, use the text-node creation facilities of the W3C DOM, which bulks up the code just a bit (changes shown in bold):

var tbodyElem = document.getElementById("myTbody");
var trElem, tdElem, txtNode;
for (var j = 0; j < tableData.length; j++) {
   trElem = tbodyElem.insertRow(tbodyElem.rows.length);
   trElem.className = "tr" + (j%2);
   tdElem = trElem.insertCell(trElem.cells.length);
   tdElem.className = "col0";
   txtNode = document.createTextNode(tableData[j].alpha);
   tdElem = trElem.insertCell(trElem.cells.length);
   tdElem.className = "col4";
   txtNode = document.createTextNode(tableData[j].epsilon);

Comparing the performance of the innerHTML and text-node creation techniques produced mixed results. IE/Windows and Safari were marginally faster using innerHTML, while Mozilla-based browsers (on both Windows and Mac test platforms) showed inverse proportions in favor of text node creation, despite the increase in script statements that execute in the process.

More significant, however, is that on the same computer, IE 6 took three to four times longer to perform the task on all 500 rows than Netscape 7 did. Opera 7 in Windows was unbearably slow. Only Safari demonstrated a performance preference for direct DOM table modification methods over the other approaches studied, accomplishing its complete task in one-third to one-fifth the time required by Mozilla 1.2 on the same Macintosh system.

Pages: 1, 2

Next Pagearrow