Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to create large static DOM elements in JavaScript?

I have many elements that one of my JS widgets needs to create and add to the DOM often. They never change.

So one option would be to store the HTML itself as a string in JS and use JQuery to create the elements from the string, then append it to the document:

var elements = "<div><table><tr><td>1</td><td>2</td></tr></table></div>"; function create() {   return $(elements); } $("body").append(create()); 

Another option is to write a function that will use document.createElement("div"), or $("<div>") many times to build the elements, append them to each other where needed, then append to the document:

function create() {   return $("<div>").append($("<table>")...... } $("body").append(create()); 

In the first case, I have a big JS string that is actually HTML. In the second case, I have an unwieldy piece of JS that actually represents HTML.

Are there (dis)advantages to one or the other? Is there a better solution I'm not thinking of?

like image 335
Tony R Avatar asked Mar 08 '12 08:03

Tony R


People also ask

Is innerHTML faster than createElement?

As for performance: InnerHTML is most definitely going to be slower, because it needs to be parsed and internally converted into DOM elements (maybe using the createElement method).

Which method is used to add components or elements to the DOM?

AppendChild. The simplest, most well-known method of appending an element to the DOM is certainly the appendChild() .

Which DOM method is supported by most browsers?

The last & final method is innerHTML, an interesting one. It's supported on mostly every browser or platform. However, it's a nonstandard element. Typically, it is used to access & write content inside XHTML elements.


2 Answers

Detailed analysis of 3 commons ways of creating DOM in JS and the best approach.

I will provide 3 ways to create large DOM and their pros and cons, and of-course the most optimized way for large DOM creation and why. Bottom line is while creating DOM in js, native JS and DOM methods are your friend, don't use Jquery unless there is no other way(which is unlikely).

Test Data for comparison: Created 400 rows with 5 columns and appended to DOM. testData is list of objects that you get from backend in json form to create table.

Attached Execution time test result snapshot for different browsersenter image description hereHTML

<div id="employeeListContainer1"></div> <table id="employeeList2">     <thead>         <tr>             <th>First Name</th>             <th>Last Name</th>             <th>Title</th>             <th>ID</th>             <th>Department</th>         </tr>     </thead> </table> 

1st way : String Concatenation (Most Optimized way in terms of performance across browsers)

var tableElementContainer1 = document.getElementById("employeeListContainer1"); var temptableHolder  = '<table><thead><tr><th>First Name</th><th>Last Name</th><th>Title</th><th>ID</th><th>Department</th></tr></thead><tbody>';  for(var i=0,len=testData.length; i<len; i++){     temptableHolder  += '<tr><td>' + testData[i].firstName + '</td><td>' + testData[i].lastName + '</td><td>' + testData[i].title         + '</td><td>' + testData[i].id + '</td><td>'  + testData[i].department +  '</td></tr>'; }  temptableHolder += '</tbody></table>'; tableElementContainer1.innerHTML  = temptableHolder ; 

Pros:

  • Fastest execution time across Firefox/Chrome/IE/Safari (3 to 5 millisec across browsers). Measured via both performance.now() and console.time() APIs.

Cons:

  • When number of columns are more and you need to set lot of attributes then working with strings can get little difficult and less main tenable.

2nd way: Native Js document.createElement()(This is 2nd best approach in terms of performance across browsers)

var tableBody = document.createElement('tbody'); var tableElement2 = document.getElementById("employeeList2");  for(var i=0,len=testData.length; i<len; i++){     tableRow = document.createElement("tr");          for(var k in testData[i]){         rowCell = document.createElement("td");         rowCell.appendChild(document.createTextNode(testData[i][k]));         tableRow.appendChild(rowCell);     }          tableBody.appendChild(tableRow); }  tableElement2.appendChild(tableBody); 

Pros:

  • 2nd fastest execution time across Firefox/Chrome/Safari (5 to 12 millisec across browsers). Measured via both performance.now() and console.time() APIs.
  • More main tenable than 1st Approach

Cons:

  • Execution time is more in IE browsers, 90+ millsec

3rd Way: Using Jquery to create DOM (My advise is don't use it)

var tableBody = $('<tbody></tbody>'); var tableElement2 = document.getElementById("employeeList2");  for(var i=0,len=testData.length; i<len; i++){     tableRow = $("<tr></tr>");          for(var k in testData[i]){         rowCell = $("<td></td>");         rowCell.append(testData[i][k]);         tableRow.append(rowCell);     }          tableBody.append(tableRow); }  tableElement2.append(tableBody); 

Pros:

  • Easy to add attributes/class/styles on elements and is easy to read and main tenable.

Cons:

  • Worst execution time across all browsers (220 ms to 330 ms), slowest numbers are in IE
like image 143
Sanjeev Avatar answered Sep 18 '22 13:09

Sanjeev


Note: If you hate reading, just check summary down below for final answer

Maybe you don't really need to create those with help of jQuery.

If the structure of that html is complicated (hence using document.createElement approach would be an overkill) I would go with innerHTML attribute.

// somewhere in your code, preferably outside of global scope var div = document.createElement('div') div.id = 'mycustomdiv' document.getElementsByTagName('body')[0].appendChild(div); // assuming elements contains string of html with your elements div.innerHTML = elements; 

That way you avoid the (assuming again) unnecessary overhead of creating and wrapping the elements in jQuery object.


Update: test for yourself what's the fastest method http://jsperf.com/creating-complex-elements. This test confirms that when you're trying to squeeze every last bit of performance revert to vanilla javascript and classic DOM operations.


Update 2. To investigate why innerHTML method on Firefox 10 have such bad results in relation to passing full string to jQuery.append, I took a look at the jQuery source.

As it turns out (in jQuery 1.7.1), they're using yet another way of creating dom elements by utilizing document.createDocumentFragment (with some fallbacks of course for browsers that don't have proper support).

DocumentFragments are DOM Nodes. They are never part of the main DOM tree. The usual use case is to create the document fragment, append elements to the document fragment and then append the document fragment to the DOM tree. In the DOM tree, the document fragment is replaced by all its children.

Since the document fragment is in memory and not part of the main DOM tree, appending children to it does not cause page reflow.

Assuming createDocumentFragment is available it turns out to be the best approach in terms of overall cross-browser performance of script.

So, to sum up:

I stand corrected. If you're looking for best performance throughout different browsers when creating new DOM elements, focus on document fragments (use jQuery if you don't want to deal with various corner cases yourself).

For more reading concerning documentFragment check this post on John Resig blog http://ejohn.org/blog/dom-documentfragments/

like image 35
WTK Avatar answered Sep 21 '22 13:09

WTK