DOM creation createElement vs innerHTML vs jQuery vs underscore.js Template

Benchmark created on


Preparation HTML

<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
<script type="text/javascript" src="http://ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js"></script>
<script type="text/javascript" src="http://documentcloud.github.com/underscore/underscore-min.js"></script>

<div id="dom-creation" style="display: none;">container for creating nodes with innerHTML</div>

<script id="template" type="text/html">
    <table>
        <% $.each(models, function(i, model) { %>
            <tr>
                <td><%- model.prop1 %></td>
                <td><%- model.prop2 %></td>
                <td><%- model.prop3 %></td>
                <td><%- model.prop4 %></td>
                <td><%- model.prop5 %></td>
            </tr>
        <% }); %>
    </table>
</script>

<script id="template-no-with" type="text/html">
    <table>
        <% $.each(obj.models, function(i, model) { %>
            <tr>
                <td><%- model.prop1 %></td>
                <td><%- model.prop2 %></td>
                <td><%- model.prop3 %></td>
                <td><%- model.prop4 %></td>
                <td><%- model.prop5 %></td>
            </tr>
        <% }); %>
    </table>
</script>

Setup

_.templateNoWith = function(str, data) {
        var c  = _.templateSettings;
        var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' +
          '__p.push(\'' +
          str.replace(/\\/g, '\\\\')
             .replace(/'/g, "\\'")
             .replace(c.escape || noMatch, function(match, code) {
               return "',_.escape(" + unescape(code) + "),'";
             })
             .replace(c.interpolate || noMatch, function(match, code) {
               return "'," + unescape(code) + ",'";
             })
             .replace(c.evaluate || noMatch, function(match, code) {
               return "');" + unescape(code).replace(/[\r\n\t]/g, ' ') + ";__p.push('";
             })
             .replace(/\r/g, '\\r')
             .replace(/\n/g, '\\n')
             .replace(/\t/g, '\\t')
             + "');return __p.join('');";
        var func = new Function('obj', '_', tmpl);
        if (data) return func(data, _);
        return function(data) {
          return func.call(this, data, _);
        };
      };
    
    var models      = [];
    var modelsHtml  = [];
    
    for (var i = 0; i < 250; i++) {
        var model = {
            prop1: 'prop1-' + i,
            prop2: 'prop2-' + i,
            prop3: 'prop3-' + i,
            prop4: 'prop4-' + i,
            prop5: 'prop5-' + i
        };
        
        models.push(model);
        
        modelsHtml.push(
            '<tr>' +
                '<td>' + model.prop1 + '</td>' +
                '<td>' + model.prop2 + '</td>' +
                '<td>' + model.prop3 + '</td>' +
                '<td>' + model.prop4 + '</td>' +
                '<td>' + model.prop5 + '</td>' +
            '</tr>'
        );
    }
    
    var models25        = models.slice(0, 25);
    var models50        = models.slice(0, 50);
    var models75        = models.slice(0, 75);
    var models100       = models.slice(0, 100);
    var models150       = models.slice(0, 150);
    var models200       = models.slice(0, 200);
    var models250       = models.slice(0, 250);
    
    var tableHtml25     = '<table>' + modelsHtml.slice(0, 25).join('') + '</table>';
    var tableHtml50     = '<table>' + modelsHtml.slice(0, 50).join('') + '</table>';
    var tableHtml75     = '<table>' + modelsHtml.slice(0, 75).join('') + '</table>';
    var tableHtml100    = '<table>' + modelsHtml.slice(0, 100).join('') + '</table>';
    var tableHtml150    = '<table>' + modelsHtml.slice(0, 150).join('') + '</table>';
    var tableHtml200    = '<table>' + modelsHtml.slice(0, 200).join('') + '</table>';
    var tableHtml250    = '<table>' + modelsHtml.slice(0, 250).join('') + '</table>';
    
    var domCreation     = document.getElementById('dom-creation');
    
    var template        = _.template(document.getElementById('template').innerHTML);
    var templateNoWith  = _.templateNoWith(document.getElementById('template-no-with').innerHTML);

Test runner

Ready to run.

Testing in
TestOps/sec
innerHtml 25 rows
    var div     = domCreation.innerHTML = tableHtml25;
    var table   = domCreation.firstChild;
ready
innerHtml 50 rows
    var div     = domCreation.innerHTML = tableHtml50;
    var table   = domCreation.firstChild;
ready
innerHtml 75 rows
    var div     = domCreation.innerHTML = tableHtml75;
    var table   = domCreation.firstChild;
ready
innerHtml 100 rows
    var div     = domCreation.innerHTML = tableHtml100;
    var table   = domCreation.firstChild;
ready
innerHtml 150 rows
    var div     = domCreation.innerHTML = tableHtml150;
    var table   = domCreation.firstChild;
ready
innerHtml 200 rows
    var div     = domCreation.innerHTML = tableHtml200;
    var table   = domCreation.firstChild;
ready
innerHtml 250 rows
    var div     = domCreation.innerHTML = tableHtml250;
    var table   = domCreation.firstChild;
ready
createElement 25 rows
    var table   = document.createElement('table');
    var models  = models25;
    var length  = models.length;
    
    for (var i = 0; i < models.length; i++) {
        var model   = models[i];
        var row     = document.createElement('tr');
        
        var cell1 = document.createElement('td');
        var text1 = document.createTextNode(model.prop1);
        cell1.appendChild(text1);
        row.appendChild(cell1);
        
        var cell2 = document.createElement('td');
        var text2 = document.createTextNode(model.prop2);
        cell2.appendChild(text2);
        row.appendChild(cell2);
        
        var cell3 = document.createElement('td');
        var text3 = document.createTextNode(model.prop3);
        cell3.appendChild(text3);
        row.appendChild(cell3);
        
        var cell4 = document.createElement('td');
        var text4 = document.createTextNode(model.prop4);
        cell4.appendChild(text4);
        row.appendChild(cell4);
        
        var cell5 = document.createElement('td');
        var text5 = document.createTextNode(model.prop5);
        cell5.appendChild(text5);
        row.appendChild(cell5);
        
        table.appendChild(row);
    }
ready
createElement 50 rows
    var table   = document.createElement('table');
    var models  = models50;
    var length  = models.length;
    
    for (var i = 0; i < models.length; i++) {
        var model   = models[i];
        var row     = document.createElement('tr');
        
        var cell1 = document.createElement('td');
        var text1 = document.createTextNode(model.prop1);
        cell1.appendChild(text1);
        row.appendChild(cell1);
        
        var cell2 = document.createElement('td');
        var text2 = document.createTextNode(model.prop2);
        cell2.appendChild(text2);
        row.appendChild(cell2);
        
        var cell3 = document.createElement('td');
        var text3 = document.createTextNode(model.prop3);
        cell3.appendChild(text3);
        row.appendChild(cell3);
        
        var cell4 = document.createElement('td');
        var text4 = document.createTextNode(model.prop4);
        cell4.appendChild(text4);
        row.appendChild(cell4);
        
        var cell5 = document.createElement('td');
        var text5 = document.createTextNode(model.prop5);
        cell5.appendChild(text5);
        row.appendChild(cell5);
        
        table.appendChild(row);
    }
ready
createElement 75 rows
    var table   = document.createElement('table');
    var models  = models75;
    var length  = models.length;
    
    for (var i = 0; i < models.length; i++) {
        var model   = models[i];
        var row     = document.createElement('tr');
        
        var cell1 = document.createElement('td');
        var text1 = document.createTextNode(model.prop1);
        cell1.appendChild(text1);
        row.appendChild(cell1);
        
        var cell2 = document.createElement('td');
        var text2 = document.createTextNode(model.prop2);
        cell2.appendChild(text2);
        row.appendChild(cell2);
        
        var cell3 = document.createElement('td');
        var text3 = document.createTextNode(model.prop3);
        cell3.appendChild(text3);
        row.appendChild(cell3);
        
        var cell4 = document.createElement('td');
        var text4 = document.createTextNode(model.prop4);
        cell4.appendChild(text4);
        row.appendChild(cell4);
        
        var cell5 = document.createElement('td');
        var text5 = document.createTextNode(model.prop5);
        cell5.appendChild(text5);
        row.appendChild(cell5);
        
        table.appendChild(row);
    }
ready
createElement 100 rows
    var table   = document.createElement('table');
    var models  = models100;
    var length  = models.length;
    
    for (var i = 0; i < models.length; i++) {
        var model   = models[i];
        var row     = document.createElement('tr');
        
        var cell1 = document.createElement('td');
        var text1 = document.createTextNode(model.prop1);
        cell1.appendChild(text1);
        row.appendChild(cell1);
        
        var cell2 = document.createElement('td');
        var text2 = document.createTextNode(model.prop2);
        cell2.appendChild(text2);
        row.appendChild(cell2);
        
        var cell3 = document.createElement('td');
        var text3 = document.createTextNode(model.prop3);
        cell3.appendChild(text3);
        row.appendChild(cell3);
        
        var cell4 = document.createElement('td');
        var text4 = document.createTextNode(model.prop4);
        cell4.appendChild(text4);
        row.appendChild(cell4);
        
        var cell5 = document.createElement('td');
        var text5 = document.createTextNode(model.prop5);
        cell5.appendChild(text5);
        row.appendChild(cell5);
        
        table.appendChild(row);
    }
ready
createElement 150 rows
    var table   = document.createElement('table');
    var models  = models150;
    var length  = models.length;
    
    for (var i = 0; i < models.length; i++) {
        var model   = models[i];
        var row     = document.createElement('tr');
        
        var cell1 = document.createElement('td');
        var text1 = document.createTextNode(model.prop1);
        cell1.appendChild(text1);
        row.appendChild(cell1);
        
        var cell2 = document.createElement('td');
        var text2 = document.createTextNode(model.prop2);
        cell2.appendChild(text2);
        row.appendChild(cell2);
        
        var cell3 = document.createElement('td');
        var text3 = document.createTextNode(model.prop3);
        cell3.appendChild(text3);
        row.appendChild(cell3);
        
        var cell4 = document.createElement('td');
        var text4 = document.createTextNode(model.prop4);
        cell4.appendChild(text4);
        row.appendChild(cell4);
        
        var cell5 = document.createElement('td');
        var text5 = document.createTextNode(model.prop5);
        cell5.appendChild(text5);
        row.appendChild(cell5);
        
        table.appendChild(row);
    }
ready
createElement 200 rows
    var table   = document.createElement('table');
    var models  = models200;
    var length  = models.length;
    
    for (var i = 0; i < models.length; i++) {
        var model   = models[i];
        var row     = document.createElement('tr');
        
        var cell1 = document.createElement('td');
        var text1 = document.createTextNode(model.prop1);
        cell1.appendChild(text1);
        row.appendChild(cell1);
        
        var cell2 = document.createElement('td');
        var text2 = document.createTextNode(model.prop2);
        cell2.appendChild(text2);
        row.appendChild(cell2);
        
        var cell3 = document.createElement('td');
        var text3 = document.createTextNode(model.prop3);
        cell3.appendChild(text3);
        row.appendChild(cell3);
        
        var cell4 = document.createElement('td');
        var text4 = document.createTextNode(model.prop4);
        cell4.appendChild(text4);
        row.appendChild(cell4);
        
        var cell5 = document.createElement('td');
        var text5 = document.createTextNode(model.prop5);
        cell5.appendChild(text5);
        row.appendChild(cell5);
        
        table.appendChild(row);
    }
ready
createElement 250 rows
    var table   = document.createElement('table');
    var models  = models250;
    var length  = models.length;
    
    for (var i = 0; i < models.length; i++) {
        var model   = models[i];
        var row     = document.createElement('tr');
        
        var cell1 = document.createElement('td');
        var text1 = document.createTextNode(model.prop1);
        cell1.appendChild(text1);
        row.appendChild(cell1);
        
        var cell2 = document.createElement('td');
        var text2 = document.createTextNode(model.prop2);
        cell2.appendChild(text2);
        row.appendChild(cell2);
        
        var cell3 = document.createElement('td');
        var text3 = document.createTextNode(model.prop3);
        cell3.appendChild(text3);
        row.appendChild(cell3);
        
        var cell4 = document.createElement('td');
        var text4 = document.createTextNode(model.prop4);
        cell4.appendChild(text4);
        row.appendChild(cell4);
        
        var cell5 = document.createElement('td');
        var text5 = document.createTextNode(model.prop5);
        cell5.appendChild(text5);
        row.appendChild(cell5);
        
        table.appendChild(row);
    }
ready
jQuery 25 rows
var table = $(tableHtml25);
ready
jQuery 50 rows
var table = $(tableHtml50);
ready
jQuery 75 rows
var table = $(tableHtml75);
ready
jQuery 100 rows
var table = $(tableHtml100);
ready
jQuery 150 rows
var table = $(tableHtml150);
ready
jQuery 200 rows
var table = $(tableHtml200);
ready
jQuery 250 rows
var table = $(tableHtml250);
ready
underscore.js 25 rows
$(template({ models: models25 }));
ready
underscore.js 50 rows
$(template({ models: models50 }));
ready
underscore.js 75 rows
$(template({ models: models75 }));
ready
underscore.js 100 rows
$(template({ models: models100 }));
ready
underscore.js 150 rows
$(template({ models: models150 }));
ready
underscore.js 200 rows
$(template({ models: models200 }));
ready
underscore.js 250 rows
$(template({ models: models250 }));
ready
underscore.js no with 25 rows
$(templateNoWith({ models: models25 }));
ready
underscore.js no with 50 rows
$(templateNoWith({ models: models50 }));
ready
underscore.js no with 75 rows
$(templateNoWith({ models: models75 }));
ready
underscore.js no with 100 rows
$(templateNoWith({ models: models100 }));
ready
underscore.js no with 150 rows
$(templateNoWith({ models: models150 }));
ready
underscore.js no with 200 rows
$(templateNoWith({ models: models200 }));
ready
underscore.js no with 250 rows
$(templateNoWith({ models: models250 }));
ready

Revisions

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