title: Best way to construct big html table
body: <p><strong>Scenario</strong>
  I'd like to construct table from pieces: header, each row in from items array, end.
  And then add it to page.</p>
  
  <p><strong>Code</strong></p>
  
  <p>Initially, I've tried to immediately add each piece via <code>$("#output").append(piece)</code>, but browser automatically closes open tags.</p>
  
  <p>So, currently, I concatenate string first and then set html. As I understood, the best way to concatenate big amount of strings is <a href="https://stackoverflow.com/questions/2610226/how-to-construct-a-long-string">to accumulate them in array</a> and then join, as <a href="https://stackoverflow.com/questions/3667469/javascript-jquery-best-way-to-insert-a-big-piece-of-code-into-dom">fastest way to set html</a> is to use <code>innerHTML</code> DOM property:</p>
  
  <pre><code>// Big array of data objects
  var items = [...]; // Big amount of items
  
  // Class, which constructs HTML
  var drawer = new UiDrawer();
  
  // Generate
  var result = [];
  
  result.push( drawer.getHeader() ); // &lt;table&gt;
  
  items.forEach(function (item) {
      result.push( drawer.getItem(item) ); // &lt;tr&gt; &lt;td&gt;item N&lt;/td&gt; &lt;/tr&gt;
  });
  
  result.push( drawer.getFooter() );
  
  // Add to page
  $("#output")[0].innerHTML = result.join(""); // &lt;/table&gt;
  </code></pre>
  
  <p>Is this a right way to do that? Can I construct html sequentially, without keeping it first in array?
  <hr />
  <strong>Testing things</strong></p>
  
  <p>So, currently three ways of doing this were mentioned:</p>
  
  <ul>
  <li>Concatenation of array and innerHTML</li>
  <li>Document Fragments</li>
  <li>jQuery DataTable plugin</li>
  </ul>
  
  <p>I've created small page to test performance of all these methods:
  <img src="https://i.stack.imgur.com/cw3IU.png" alt="enter image description here"></p>
  
  <p>So, array concatenation is, probably, the fastest way.</p>
  
  <p>Here simple code, which was used to test those approaches:</p>
  
  <pre><code>&lt;!DOCTYPE html&gt;
  &lt;html&gt;
      &lt;head&gt;
          &lt;link rel="stylesheet" type="text/css" href="http://cdn.datatables.net/1.10.1/css/jquery.dataTables.css"&gt;       
          &lt;script type="text/javascript" charset="utf8" src="http://code.jquery.com/jquery-1.10.2.min.js"&gt;&lt;/script&gt;       
          &lt;script type="text/javascript" charset="utf8" src="http://cdn.datatables.net/1.10.1/js/jquery.dataTables.js"&gt;&lt;/script&gt;
      &lt;/head&gt;
      &lt;body&gt;
          &lt;div id="meta"&gt;&lt;/div&gt;
          &lt;div id="output"&gt;&lt;/div&gt;
          &lt;script&gt;
              var meta = document.getElementById("meta");
              var output = document.getElementById("output");
              var rowsNumber = 10000;
  
              var items = [];
              for (var i = 0; i &lt; rowsNumber; i++) {
                  items.push(["#" + i, "Simple item"]);
              }           
  
              // Evaluates given function
              var evaluateWay = function(name, func) {
                  var start = new Date();
  
                  for (var i = 0; i &lt; 10; i++) {
                      func();
                      output.innerHTML = "";
                  }
  
                  var finish = new Date();
  
                  meta.innerHTML += "Ten iterations to draw table with " + items.length + " rows via '" + name + "' way took " + (finish - start) + " ms&lt;br /&gt;";
                  output.innerHTML = "";
              };
  
              // Array concatenation
              evaluateWay("Array concatenation", function () {
                  var result = [];
  
                  result.push( "&lt;table&gt;" );
  
                  items.forEach(function (item) {
                      result.push( "&lt;tr&gt; &lt;td&gt;" + item[0] + "&lt;/td&gt;&lt;td&gt;" + item[1] + "&lt;/td&gt; &lt;/tr&gt;" );
                  });
  
                  result.push( "&lt;/table&gt;" );
  
                  // Add to page
                  output.innerHTML = result.join(""); // &lt;/table&gt;
              });
  
              // Document Fragments
              evaluateWay("Document Fragments", function () {
                  var table = document.createElement('table');
  
                  items.forEach(function (item) {
                      var row = document.createElement('tr');
  
                      var cell1 = document.createElement('td');
                      var cell2 = document.createElement('td');
                      cell1.innerHTML = item[0];
                      cell2.innerHTML = item[1];
                      row.appendChild(cell1);
                      row.appendChild(cell2);
  
                      table.appendChild(row);
                  });
  
                  output.appendChild(table);
              });
  
              // jQuery Table Plugin
              evaluateWay("jQuery Table Plugin", function () {
                  output.innerHTML = '&lt;table id="myTable"&gt;&lt;/table&gt;';
                  $('#myTable').dataTable( {
                      "data": items,
                      "columns": [
                          { },
                          { },
                      ]
                  } ); 
              });
          &lt;/script&gt;
      &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>