JavaScript template language shootoff

JavaScript performance comparison

Revision 83 of this test case created by Boris Moore

Info

A brief comparison of some JavaScript templating engines on a short template: 6 header tags, and 10 list items.

Note: When adding a new test, please ensure that your test returns the same HTML string (or equivalent DOM fragment) as the others.

Preparation code

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>

<script src="http://documentcloud.github.com/underscore/underscore.js"></script>

<script src="http://github.com/janl/mustache.js/raw/master/mustache.js"></script>

<script src="https://github.com/downloads/paul/handlebars.js/handlebars.js"></script>

<script src="http://gist.github.com/raw/550881/29bb186167079c0b33ab6e9d50d779f37860cfa4/micro.js"></script>

<script src="http://github.com/creationix/haml-js/raw/master/lib/haml.js"></script>

<script src="http://gist.github.com/raw/550723/12d176698628e30a1df398c7ac7aea93924e1294/jade.js"></script>

<script src="http://jashkenas.github.com/coffee-script/extras/coffee-script.js"></script>
<script src="http://sstephenson.github.com/eco/dist/eco.js"></script>

<script src="https://github.com/jquery/jquery-tmpl/raw/master/jquery.tmpl.min.js"></script>

<script src="https://github.com/olado/doT/raw/master/doT.js"></script>

<script src="https://github.com/olado/doT/raw/master/doU.js"></script>

<script src="http://github.com/aefxx/jQote2/raw/69b2053a13f5f180e696de9b3dba856a3c00678c/jquery.jqote2.js"></script>

<script src="http://embeddedjavascript.googlecode.com/files/ejs_0.9_alpha_1_production.js"></script>

<script src="http://github.com/pure/pure/raw/master/libs/pure.js"></script>
<div class="pure">
        <h1 class='header'></h1>
        <h2 class='header2'></h2>
        <h3 class='header3'></h3>
        <h4 class='header4'></h4>
        <h5 class='header5'></h5>
        <h6 class='header6'></h6>
        <ul class='list'>
                <li class='item'></li>
        </ul>
</div>

<script src="https://github.com/douglascrockford/JSON-js/raw/master/json2.js"></script>


<script>
  window.mustacheTemplate = "<div><h1 class='header'>{{header}}</h1><h2 class='header2'>{{header2}}</h2><h3 class='header3'>{{header3}}</h3><h4 class='header4'>{{header4}}</h4><h5 class='header5'>{{header5}}</h5><h6 class='header6'>{{header6}}</h6><ul class='list'>{{#list}}<li class='item'>{{.}}</li>{{/list}}</ul></div>";
 
  window.handlebarsTemplate = Handlebars.compile("<div><h1 class='header'>{{header}}</h1><h2 class='header2'>{{header2}}</h2><h3 class='header3'>{{header3}}</h3><h4 class='header4'>{{header4}}</h4><h5 class='header5'>{{header5}}</h5><h6 class='header6'>{{header6}}</h6><ul class='list'>{{#each list}}<li class='item'>{{this}}</li>{{/each}}</ul></div>");
 
  window.micro = "<div><h1 class='header'><%= header %></h1><h2 class='header2'><%= header2 %></h2><h3 class='header3'><%= header3 %></h3><h4 class='header4'><%= header4 %></h4><h5 class='header5'><%= header5 %></h5><h6 class='header6'><%= header6 %></h6><ul class='list'><% for (var i = 0, l = list.length; i < l; i++) { %><li class='item'><%= list[i] %></li><% } %></ul></div>";
 
  window.underscoreTemplate = _.template(micro);
 
  window.resigTemplate = tmpl(micro);
 
  window.sharedVariables = {
   header: "Header",
   header2: "Header2",
   header3: "Header3",
   header4: "Header4",
   header5: "Header5",
   header6: "Header6",
   list: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
  };
 
  window.jadeTemplate = "div\n  h1.header!= header\n  h2.header2!= header2\n  h3.header3!= header3\n  h4.header4!= header4\n  h5.header5!= header5\n  h6.header6!= header6\n  ul.list\n    - each item in list\n      li.item!= item";
 
  window.hamlTemplate = Haml("%div\n  %h1.header= header\n  %h2.header2= header2\n  %h3.header3= header3\n  %h4.header4= header4\n  %h5.header5= header5\n  %h6.header6= header6\n  %ul.list\n    :each item in list\n      %li.item= item");
 
  window.ecoTemplate = eco("<div><h1 class='header'><%- @header %></h1><h2 class='header2'><%- @header2 %></h2><h3 class='header3'><%- @header3 %></h3><h4 class='header4'><%- @header4 %></h4><h5 class='header5'><%- @header5 %></h5><h6 class='header6'><%- @header6 %></h6><ul class='list'><% for item in @list: %><li class='item'><%- item %></li><% end %></ul></div>");
 
  window.jQueryTemplate = $.template(null, "<div><h1 class='header'>{{html header}}</h1><h2 class='header2'>{{html header2}}</h2><h3 class='header3'>{{html header3}}</h3><h4 class='header4'>{{html header4}}</h4><h5 class='header5'>{{html header5}}</h5><h6 class='header6'>{{html header6}}</h6><ul class='list'>{{each list}}<li class='item'>{{html $value}}</li>{{/each}}</ul></div>");
 
  window.doTtemplate = doT.template("<div><h1 class='header'>{{= it.header }}</h1><h2 class='header2'>{{= it.header2 }}</h2><h3 class='header3'>{{= it.header3 }}</h3><h4 class='header4'>{{= it.header4 }}</h4><h5 class='header5'>{{= it.header5 }}</h5><h6 class='header6'>{{= it.header6 }}</h6><ul class='list'>{{ for (var i = 0, l = it.list.length; i < l; i++) { }}<li class='item'>{{= it.list[i] }}</li>{{ } }}</ul></div>");
 
  window.doUtemplate = doU.template("<div><h1 class='header'>{{= it.header }}</h1><h2 class='header2'>{{= it.header2 }}</h2><h3 class='header3'>{{= it.header3 }}</h3><h4 class='header4'>{{= it.header4 }}</h4><h5 class='header5'>{{= it.header5 }}</h5><h6 class='header6'>{{= it.header6 }}</h6><ul class='list'>{{ for (var i = 0, l = it.list.length; i < l; i++) { }}<li class='item'>{{= it.list[i] }}</li>{{ } }}</ul></div>");
 
  window.jqote_tmpl = "<div><h1 class='header'><%= this.header %></h1><h2 class='header2'><%= this.header2 %></h2><h3 class='header3'><%= this.header3 %></h3><h4 class='header4'><%= this.header4 %></h4><h5 class='header5'><%= this.header5 %></h5><h6 class='header6'><%= this.header6 %></h6><ul class='list'><% for (var n = 0, l = this.list.length; n < l; n++) { %><li class='item'><%= this.list[n] %></li><% } %></ul></div>";
 
  window.jqote2 = $.jqotec(jqote_tmpl);
 
  window.ejs = new EJS({
   text: micro
  });
 
  window.baseHtml = "<div><h1 class='header'></h1><h2 class='header2'></h2><h3 class='header3'></h3><h4 class='header4'></h4><h5 class='header5'></h5><h6 class='header6'></h6><ul class='list'><li class='item'></li></ul></div>";
 
  window.pureTemplate = $p('div.pure').compile({
   h1: 'header',
   h2: 'header2',
   h3: 'header3',
   h4: 'header4',
   h5: 'header5',
   h6: 'header6',
   li: {
    'itm<-list': {
     '.': 'itm'
    }
   }
  });
 
  window.hamlTemplate_2 = "%div\n  %h1.header= header\n  %h2.header2= header2\n  %h3.header3= header3\n  %h4.header4= header4\n  %h5.header5= header5\n  %h6.header6= header6\n  %ul.list\n    :each item in list\n      %li.item= item";
  window.hamlCompiled = Haml.compile(hamlTemplate_2);
  window.hamlOptimized = Haml.optimize(hamlCompiled);
</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
Mustache.js Template
Mustache.to_html(mustacheTemplate, sharedVariables);
pending…
Resig Micro-Templating.
resigTemplate(sharedVariables);
pending…
Creationix's Haml-js Template
hamlTemplate(sharedVariables);
pending…
Jade Template
jade.render(jadeTemplate, {
 locals: sharedVariables,
 filename: 'test.js',
 cache: true
});
pending…
Underscore.js Template
underscoreTemplate(sharedVariables);
pending…
Eco Template
ecoTemplate(sharedVariables);
pending…
jQuery Templates
jQueryTemplate($, {
 data: sharedVariables
}).join("");
pending…
Handlebars.js
handlebarsTemplate(sharedVariables);
pending…
doT.js
doTtemplate(sharedVariables);
pending…
doU.js
doUtemplate(sharedVariables);
pending…
jQote2 direct
jqote2.call(sharedVariables, 0, 0, [sharedVariables], jqote2);
pending…
ejs
ejs.render(sharedVariables);
pending…
Pure
pureTemplate(sharedVariables);
pending…
Creationix's Haml-js Template (compiled & optimized)
Haml.execute(window.hamlOptimized, sharedVariables, sharedVariables);
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:

2 comments

Boris Moore (revision owner) commented :

The test for jQuery Templates was incorrect in that a) it incorrectly used an API that is designed to be chained with .appendTo() for DOM insertion, and b) the template used the ${value} tag, which HTML encodes, whereas other templates are not HTML encoding. {{html value}} is the correct tag to use. I have corrected the tests to return a string, and not HTML encode.

aefxx commented :

Boris is right, that was like comparing apples and oranges. On the other hand, jQuery Template still performs poorly compared to the top performers. Where's the overhead, Boris?

Add a comment