Javascript efficiently creates a table from JSON and adds it to the DOM

I have a JSON array coming from a server with an array of 200 objects, each of which contains 10 more objects that I want to display in a table format. First, I created a <tr> for each iteration, and using jQuery I added a <td> built from the array values ​​to the <tr> . It took about 30 seconds in Chrome and 19 seconds in IE 8. It took too much time, so I tried to switch to the Array.join() method, where I would save every row that will make up the whole table in the array, and to the end do $('#myTable').append(textToAppend) . This is actually worse than my first version by about 5 seconds.

I would like to get this in about 10 seconds. Do I have a chance at that? If not, I will just add one line at a time, but I would prefer not to.

 for(allIndex = 0; allIndex < entries.alumnus.length; allIndex++){ var entry = '<tr id="entry' + allIndex + '" class="entry"></tr>'; $('#content_table').append(entry); $('#entry' + allIndex).append(($.trim(entries.alumnus[allIndex].title) != '' ? '<td id="title' + allIndex + '" class="cell"><span class="content">' + entries.alumnus[allIndex].title + '</span></td>' : '<td width="5%">' + filler + '</td>')); . . . .//REST OF ELEMENTS . . . } 

UPDATE: I must have mixed up something yesterday because I went back to trying to add elements from the DOM and then connected them later without using jQuery, and I got my time up to 85 ms in Chrome and 450 ms in IE7 !! ! You guys are awesome !!! I gave user1 an answer because this one was more comprehensive and using fragments didn't change my time very much in Chrome and added about 20 ms in IE7. But I still appreciate @Emre Erkan's answer and will use it more often :)

+8
performance javascript jquery string concatenation
source share
5 answers

The fastest will look something like this:

 var oldTable = document.getElementById('example'), newTable = oldTable.cloneNode(true); for(var i = 0; i < json_example.length; i++){ var tr = document.createElement('tr'); for(var j = 0; j < json_example[i].length; j++){ var td = document.createElement('td'); td.appendChild(document.createTextNode(json_example[i][j])); tr.appendChild(td); } newTable.appendChild(tr); } oldTable.parentNode.replaceChild(newTable, oldTable); 

And should work in milliseconds. Here is an example: http://jsfiddle.net/Paulpro/YhQEC/ It creates 200 rows of a table, each of which contains 10 td.

You want to add elements, not strings, but you don't want to add anything to the DOM until you finish creating the whole structure (to avoid overflow in your loop). This way you can clone the source table and join the clone, and then insert the clone after the loop ends.

You will also get pretty high speed by avoiding jQuery and interacting directly with the DOM.

Your code might look like this:

 var oldTable = document.getElementById('content_table'), newTable = oldTable.cloneNode(true), tr, td; for(var i = 0; i < entries.alumnus.length.length; i++){ tr = document.createElement('tr'); tr.id = 'entry' + i; tr.className = 'entry'; if(entries.alumnus[i].title){ td = document.createElement('td'); td.id = 'title' + i; td.className = 'cell'; var span = document.createElement('span'); span.className = 'content'; span.appendChild(document.createTextNode(entries.alumnus[i].title); td.appendChild(span); tr.appendChild(td); tr.appendChild(createFiller(filler)); } // REST OF ELEMENTS newTable.appendChild(tr); } oldTable.parentNode.replaceChild(newTable, oldTable); function createFiller(filler){ var td = document.createElement('td'); td.style.width = '5%'; td.appendChild(document.createTextNode(filler); return td; } 
+13
source share

I suggest you use DocumentFragment and use your own javascript for this kind of massive DOM manipulation. I prepared an example, you can check it here .

 var fragment = document.createDocumentFragment(), tr, td, i, il, key; for(i=0,il=data.length;i<il;i++) { tr = document.createElement('tr'); for(key in data[i]) { td = document.createElement('td'); td.appendChild( document.createTextNode( data[i][key] ) ); tr.appendChild( td ); } fragment.appendChild( tr ); } $('#mytable tbody').append( fragment ); 

I think this is the fastest way to do such a job.

+9
source share

The most important thing is to create all the table content from dom, and then paste it into the table. This chrome ends in about 3 to 5 ms:

 function createTableFromData(data) { var tableHtml = ''; var currentRowHtml; for (var i = 0, length = data.length; i < length; i++) { currentRowHtml = '<tr><td>' + data[i].join('</td><td>') + '</td></tr>'; tableHtml += currentRowHtml; } return tableHtml; } var textToAppend= createTableFromData(yourData); $('#myTable').append(textToAppend); 
+5
source share

If you have a JSON test string from the server, and the structure reliably represents an array of string arrays, then below you can avoid JSON analysis and instead replace HTML generation with a constant sequence of regular expressions which, as a rule, are implemented in native code that uses its own buffers. This should completely eliminate one parsing and replace any buffer copies that cost O (n ** 2) with k, O (n) buffer copies for constant k.

 var jsonContent = ' [ [ "foo", "bar", "[baz\\"boo\\n]" ], ["1","2" , "3"] ] '; var repls = { // Equivalent inside a JSON string. ',': "\\u002b", '[': "\\u005b", ']': "\\u005d" }; var inStr = false; // True if the char matched below is in a string. // Make sure that all '[', ']', and ',' chars in JSON content are // actual JSON punctuation by re-encoding those that appear in strings. jsonContent = jsonContent.replace(/[\",\[\]]|\\./g, function (m) { if (m.length === 1) { if (m === '"') { inStr = !inStr; } else if (inStr) { return repls[m]; } } return m; }); // Prevent XSS. jsonContent = jsonContent.replace(/&/g, "&amp;") .replace(/</g, "&lt;"); // Assumes that the JSON generator does not encode '<' as '\u003c'. // Remove all string delimiters and space outside of strings. var html = jsonContent .replace(/\"\s*([,\]])\s*\"?|\s*([\[,])\s*\"/g, "$1$2"); // Introduce the table header and footer. html = html.replace(/^\s*\[/g, "<table>") html = html.replace(/]\s*$/g, "</table>") // Introduce row boundaries. html = html.replace(/\],?/g, "</tr>") html = html.replace(/\[/g, "<tr><td>") // Introduce cell boundaries. html = html.replace(/,/g, "<td>") // Decode escape sequences. var jsEscs = { '\\n': '\n', '\\f': '\f', '\\r': '\r', '\\t': '\t', '\\v': '\x0c', '\\b': '\b' }; html = html.replace(/\\(?:[^u]|u[0-9A-Fa-f]{4})/g, function (m) { if (m.length == 2) { // Second branch handles '\\"' -> '"' return jsEscs[m] || m.substring(1); } return String.fromCharCode(parseInt(m.substring(2), 16)); }); // Copy and paste with the below to see the literal content and the table. var pre = document.createElement('pre'); pre.appendChild(document.createTextNode(html)); document.body.appendChild(pre); var div = document.createElement('div'); div.innerHTML = html; document.body.appendChild(div); 
+1
source share

It definitely fits. I don't think string concatenation is the way to go. In general, it seems faster to create and manipulate elements when they are not tied to the main DOM; so first create the whole table and add it. In simple javascript, I think the code below is basically what you want to achieve.

  //mock up the data (this will come from you AJAX call).. var data = []; for(var i = 0; i < 200; i++){ var rowData = []; for(var j = 0; j < 10; j++){ rowData.push("This is a string value"); } data.push(rowData); } //create table.. var table = document.createElement("table"); for(var i = 0; i < data.length; i++){ var rowData = data[i]; var row = document.createElement("tr"); for(var j = 0; j < rowData.length; j++){ var cell = document.createElement("td"); cell.innerHTML = rowData[j]; row.appendChild(cell); } table.appendChild(row); } //finally append the whole thing.. document.body.appendChild(table); 

When I paste this into the console in Safari, it starts in <1 second, so you should be fine.

0
source share

All Articles