first-pass

JavaScript performance comparison

Revision 8 of this test case created by blid

Preparation code

<script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js">
</script>
<script src="//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

Test

Test runner

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

Java applet disabled.

Testing in unknown unknown
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. Here’s a list of current revisions for this page:

0 comments

Add a comment