Handlebars VS TemplateEngine

JavaScript performance comparison

Revision 8 of this test case created by Jason Miller

Info

Libraries

Handlebars.js (current)
vs
Mustache.js (current)
vs
TemplateEngine (current, 1.8)

Notes

Preparation code

<script src="http://jsonupload.services.jasonmillerdesign.com/file/4085966784759edf34d5ce919d935b90_16d7a767a3603d75eb65cd83ef111755/TemplateEngine-1.8.js"></script>

<script src="http://cloud.github.com/downloads/wycats/handlebars.js/handlebars-1.0.0.beta.6.js"></script>

<script src="//cdnjs.cloudflare.com/ajax/libs/mustache.js/0.7.2/mustache.js"></script>


<button onclick="var n=document.getElementById('o').style;n.display=n.display=='none'?'block':'none';">Toggle Output</button>
<div id="o" style="display:none;">
  <div class="output">
    <h1>TemplateEngine</h1>
    <div id="output_engine"></div>
  </div>
  <div class="output">
    <h1>Handlebars</h1>
    <div id="output_handlebars"></div>
  </div>
  <div class="output">
    <h1>Mustache</h1>
    <div id="output_mustache"></div>
  </div>
</div>


<script id="template-handlebars" type="text/template"><![CDATA[
    <div class="foo1">
        <h2>{{title}}</h2>
        <h4>Iterating over an object:</h4>
        <ul>
            {{#each list}}
                <li>{{.}}</li>
            {{/each}}
        </ul>
        <h4>Iterating over an array:</h4>
        <ol>
            {{#arr}}
                <li>{{.}}</li>
            {{/arr}}
        </ol>
        <h4>Recursive nesting:</h4>
        <ul>
            {{#each nest1}}
                <li>
                    <div>key={{__key__}}</div>
                    <ol>
                        {{#.}}
                            <li>{{.}}</li>
                        {{/.}}
                    </ol>
                </li>
            {{/each}}
        </ul>
    </div>
]]></script>


<script id="template-engine" type="text/template"><![CDATA[
    <div class="foo1">
        <h2>{{title}}</h2>
        <h4>Iterating over an object:</h4>
        <ul>
            {{#each list}}
                <li>{{.}}</li>
            {{/each}}
        </ul>
        <h4>Iterating over an array:</h4>
        <ol>
            {{#each arr}}
                <li>{{.}}</li>
            {{/each}}
        </ol>
        <h4>Recursive nesting:</h4>
        <ul>
            {{#each nest1}}
                <li>
                    <div>key={{__key__}}</div>
                    <ol>
                        {{#each .}}
                            <li>{{.}}</li>
                        {{/each}}
                    </ol>
                </li>
            {{/each}}
        </ul>
    </div>
]]></script>


<script id="template-mustache" type="text/template"><![CDATA[
    <div class="foo1">
        <h2>{{title}}</h2>
        <h4>Iterating over an object:</h4>
        <ul>
            {{#list}}
                <li>{{value}}</li>
            {{/list}}
        </ul>
        <h4>Iterating over an array:</h4>
        <ol>
            {{#arr}}
                <li>{{.}}</li>
            {{/arr}}
        </ol>
        <h4>Recursive nesting:</h4>
        <ul>
            {{#nest1}}
                <li>
                    <div>key={{__key__}}</div>
                    <ol>
                        {{#value}}
                            <li>{{.}}</li>
                        {{/value}}
                    </ol>
                </li>
            {{/nest1}}
        </ul>
    </div>
]]></script>



<script>
/** NOTE: Handlebars does not support #each for Objects by default. We have to re-implement the each block helper to get that functionality back. The code below is a slightly modified version of the example from the Handlebars website. */
Handlebars.registerHelper('each', function(context, options) {
    var ret = "";
    for(var i in context) {
        if (context.hasOwnProperty(i)) {
            ret = ret + options.fn(context[i]);
        }
    }
    return new Handlebars.SafeString(ret);
});

//----------------------------

// Collect Templates:
var templates = {};
var tpls = document.querySelectorAll('script[type="text/template"]');
[].forEach.call(tpls, function(n) {
    var tpl = (n.textContent || n.nodeValue || '');
    tpl = tpl.replace(/(^<\!\[CDATA\[|\]\]>$)/gm,'');
    templates[n.id.replace(/^template\-/gi,'')] = tpl;
});

// Output Areas:
var out = {
    engine : document.getElementById('output_engine'),
    handlebars : document.getElementById('output_handlebars'),
    mustache : document.getElementById('output_mustache')
};

var output = {};

var context = {
        title : "Template Standoff",
        list : {
            test : "test value",
            test2 : "test 2 value",
            test3 : "test 3 value",
        },
        arr : [
            "array value 1",
            "array value 2",
            "array value 3",
            "array value 4"
        ],
        nest1 : {
            foo : [
                "nested level 2, item 1, child 1",
                "nested level 2, item 1, child 2",
                "nested level 2, item 1, child 3"
            ],
            foo2 : [
                "nested level 2, item 2, child 1",
                "nested level 2, item 2, child 2"
            ],
            foo3 : [
                "nested level 2, item 3, child 1",
                "nested level 2, item 3, child 2",
                "nested level 2, item 3, child 3",
                "nested level 2, item 3, child 4"
                ]
        }
    };

function listify(obj) {
    var list=[], item, p, i;
    for (p in obj) {
        if (obj.hasOwnProperty(p)) {
            item = {
                __key__ : p,
                value : obj[p]
            };
            if (obj && typeof obj[p]==='object') {
                for (i in obj[p]) {
                    if (obj[p].hasOwnProperty(i)) {
                        item[i] = obj[p][i];
                    }
                }
            }
            list.push(item);
        }
    }
    return list;
}

var crappyContext = {
    title : context.title,
    list : listify(context.list),
    arr : context.arr,
    nest1 : listify(context.nest1)
};
</script>
<script>
Benchmark.prototype.setup = function() {
    var compiled;
};

Benchmark.prototype.teardown = function() {
    out.engine.innerHTML = output.engine;
    out.handlebars.innerHTML = output.handlebars;
    out.mustache.innerHTML = output.mustache;
   
};
</script>

Preparation code output

Test runner

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

Java applet disabled.

Testing in unknown unknown
Test Ops/sec
Handlebars
compiled = Handlebars.compile(templates.handlebars);
output.handlebars = compiled(context);
 
pending…
Mustache
// crappyContext is a specialized context object for mustache
// ... since mustache can't iterate over objects
output.mustache = Mustache.to_html(templates.mustache, crappyContext);
pending…
TemplateEngine
output.engine = engine_1_8.template(templates.engine, context);
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