first-pass

JavaScript performance comparison

Revision 8 of this test case created by blid

Preparation code

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.2/underscore-min.js">
</script>
<table id="test_table">
  <tbody id="test_tbody">
    Test
  </tbody>
</table>
<style>
  .active{ background:red; font-size:30px; }
</style>
<script type="text/template" id="template">
  < %
  for (var i = 0; i < rows; i++) { % > < tr > < %
    for (var j = 0; j < data.length; j++) { % > < td > < %= data[j] % > < /td>
    <% } %>
    </tr > < %
    } % >
</script>
      
<script>
Benchmark.prototype.setup = function() {
  // Tables
  var numItems = 5; // items/cols
  var rows = 5;
  var tbody = document.getElementById('test_tbody');
  var $tbody = $('#test_tbody');
  var tr, td;
  var $tr, $td;
  
  // Data arrays
  var dataArray = [];
  var dataArrayObject = [];
  
  // Fragments
  var frag = document.createDocumentFragment();
  var frag2 = document.createDocumentFragment();
  
  // Populate data
  for (var i = 0; i < numItems; i++) {
    dataArray[i] = i;
  }
  
  for (var i = 0; i < numItems; i++) {
    dataArrayObject[i] = {};
    dataArrayObject[i]["id"] = i;
  }
  
  var predefinedLengthArray = new Array(50);
  for (i = 0; i < numItems; i++) {
    predefinedLengthArray[i] = dataArray[i];
  }
  
  
  function drawDocumentFragTable(cols) {
    for (var i = 0; i < rows; i++) {
      tr = document.createElement('tr');
      for (var j = 0; j < cols.length; j++) {
        td = document.createElement('td');
        td.appendChild(document.createTextNode(cols[j]));
  
        frag2.appendChild(td);
      }
      tr.appendChild(frag2);
      frag.appendChild(tr);
    }
    tbody.appendChild(frag);
  }
  
  
  function eventsNoDelegation() {
    $('table td').on('click', function() {
      $(this).toggleClass('active');
    });
  }
  
  function eventsWithDelegation() {
    $('table').on('click', 'td', function() {
      $(this).toggleClass('active');
    });
  }
  
  
  // Array object, no delegation, jQuery for table creation.
  var moduleA = function() {
  
      return {
  
        data: dataArrayObject,
  
        init: function() {
          this.addTable();
          this.addEvents();
        },
  
        addTable: function() {
  
          for (var i = 0; i < rows; i++) {
            $tr = $('<tr></tr>');
            for (var j = 0; j < this.data.length; j++) {
              $tr.append('<td>' + this.data[j]["id"] + '</td>');
            }
            $tr.appendTo($tbody);
          }
  
        },
        addEvents: function() {
          eventsNoDelegation();
        }
  
      };
  
      }();
  
  
  
  
  // Simple array, no delegation, jQuery for table creation
  var moduleB = function() {
  
      return {
  
        data: dataArray,
  
        init: function() {
          this.addTable();
          this.addEvents();
        },
        addTable: function() {
          for (var i = 0; i < rows; i++) {
            $tr = $('<tr></tr>');
            for (var j = 0; j < this.data.length; j++) {
              $tr.append('<td>' + this.data[j]["id"] + '</td>');
            }
            $tr.appendTo($tbody);
          }
        },
        addEvents: function() {
          eventsNoDelegation();
        }
  
      };
  
      }();
  
  
  // Simple array, delegation, jQuery for table creation.
  var moduleC = function() {
  
      return {
  
        data: dataArray,
  
        init: function() {
          this.addTable();
          this.addEvents();
        },
        addTable: function() {
          for (var i = 0; i < rows; i++) {
            $tr = $('<tr></tr>');
            for (var j = 0; j < this.data.length; j++) {
              $tr.append('<td>' + this.data[j]["id"] + '</td>');
            }
            $tr.appendTo($tbody);
          }
        },
        addEvents: function() {
          eventsWithDelegation();
        }
  
      };
  
      }();
  
  
  // Simple array, delegation, documentFragment
  var moduleD = function() {
  
      return {
  
        data: dataArray,
  
        init: function() {
          this.addTable();
          this.addEvents();
        },
        addTable: function() {
          drawDocumentFragTable(this.data);
        },
        addEvents: function() {
          eventsWithDelegation();
        }
  
      };
  
      }();
  
  
  // Simple array, delegation, documentFragment, prototypes
  moduleE = function() {};
  
  moduleE.prototype.data = dataArray;
  moduleE.prototype.init = function() {
    this.addTable();
    this.addEvents();
  };
  
  moduleE.prototype.addTable = function() {
    drawDocumentFragTable(this.data);
  };
  
  moduleE.prototype.addEvents = function() {
    eventsWithDelegation();
  };
  
  
  var modE = new moduleE();
  
  
  // Same, but with a predefined length array
  moduleF = function() {};
  
  moduleF.prototype.data = predefinedLengthArray;
  moduleF.prototype.init = function() {
    this.addTable();
    this.addEvents();
  };
  moduleF.prototype.addTable = function() {
    drawDocumentFragTable(this.data);
  };
  moduleF.prototype.addEvents = function() {
    eventsWithDelegation();
  };
  
  var modF = new moduleF();
  
  
  // Same, but with underscore templating
  moduleG = function() {};
  
  moduleG.prototype.data = dataArray;
  moduleG.prototype.init = function() {
    this.addTable();
    this.addEvents();
  };
  moduleG.prototype.addTable = function() {
    var template = _.template($('#template').text());
    var html = template({
      'data': this.data,
      'rows': rows
    });
    $tbody.append(html);
  };
  moduleG.prototype.addEvents = function() {
    eventsWithDelegation();
  };
  
  var modG = new moduleG();
  
  
  // Simple array, caching table, event delegation
  var moduleX = function() {
  
      return {
  
        data: dataArray,
  
        init: function() {
          this.addTable();
          this.addEvents();
        },
        addTable: function() {
          var cache = '';
          for (var i = 0; i < rows; i++) {
            cache += '<tr>';
  
            for (var j = 0; j < this.data.length; j++) {
              cache += '<td>' + this.data[j]["id"] + '<td>';
  
            }
            cache += '</tr>';
  
          }
          $tbody.html(cache);
        },
        addEvents: function() {
          eventsWithDelegation();
        }
  
      };
  
      }();

};

Benchmark.prototype.teardown = function() {
  rows = null;
  dataArray = null;
  dataArrayObject = null;
  predefinedLengthArray = null;
  
  $tbody.empty();
  
  tbody = null;
  $tbody = null;
  
  tr = null;
  td = null;
  $tr = null;
  $td = null;
  frag = null;
  frag2 = null;
  moduleA = null;
  moduleB = null;
  moduleC = null;
  moduleD = null;
  moduleE = null;
  moduleF = null;
  moduleG = null;
  modE = null;
  modF = null;
  modG = null;
  
  // Remove all event handlers for these
  $("table td").off("click", "**");

};
</script>

Preparation code output

<table id="test_table"> <tbody id="test_tbody"> Test </tbody> </table> <style> .active{ background:red; font-size:30px; } </style>

Test runner

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

Testing in CCBot 2.0.0 / Other 0.0.0
Test Ops/sec
Module A
// Module A - no event delegation, array objects, jQuery for table creation
moduleA.init();
pending…
Module B
// Module B - no event delegation, simple arrays, jQuery for table creation
moduleB.init();
pending…
Module C
// Module C - event delegation, simple arrays, jQuery for table creation
moduleC.init();
pending…
Module D
// Module D - event delegation, simple arrays, documentFragment for table creation
moduleD.init();
pending…
Module X
// With cache
moduleX.init();
pending…

Compare results of other browsers

Revisions

You can edit these tests or add even more tests to this page by appending /edit to the URL.

0 Comments

Test