JavaScript template language shootoff

JavaScript performance comparison

Revision 200 of this test case created by Todd Anglin

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>

<!--NOTE: Need to load from CDNJS since GitHub uses text/plain MIME type, which is blocked in IE9-->
<!--<script src="http://github.com/janl/mustache.js/raw/master/mustache.js"></script>-->
<script src="http://ajax.cdnjs.com/ajax/libs/mustache.js/0.3.0/mustache.min.js"></script>

<script src="https://github.com/downloads/wycats/handlebars.js/handlebars.1.0.0.beta.3.js"></script>

<script src="http://cdn.kendostatic.com/2011.2.804/js/kendo.all.min.js"></script>

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

<!--NOTE: Need to load from MSFT CDN since GitHub uses text/plain MIME type, which is blocked in IE9-->
<!--<script src="http://github.com/jquery/jquery-tmpl/raw/master/jquery.tmpl.min.js"></script>-->
<script src="http://ajax.microsoft.com/ajax/jquery.templates/beta1/jquery.tmpl.min.js"></script>

<!--External Template Definitions-->
<script type="text/x-kendo-template" id="kendoUIextTemplate">
<div>
<h1 class='header'><#= data.header #></h1>
<h2 class='header2'><#= data.header2 #></h2>
<h3 class='header3'><#= data.header3 #></h3>
<h4 class='header4'><#= data.header4 #></h4>
<h5 class='header5'><#= data.header5 #></h5>
<h6 class='header6'><#= data.header6 #></h6>
<ul class='list'>
   <# for (var i = 0, l = data.list.length; i < l; i++) { #>
   <li class='item'><#= data.list[i] #></li>
   <# } #>
</ul>
</div>
</script>
<script>
  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.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.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.kendouiTemplate = kendo.template("<div><h1 class='header'><#= data.header #></h1><h2 class='header2'><#= data.header2 #></h2><h3 class='header3'><#= data.header3 #></h3><h4 class='header4'><#= data.header4 #></h4><h5 class='header5'><#= data.header5 #></h5><h6 class='header6'><#= data.header6 #></h6><ul class='list'><# for (var i = 0, l = data.list.length; i < l; i++) { #><li class='item'><#= data.list[i] #></li><# } #></ul></div>", {useWithBlock:true});
  
  window.kendouiTemplate2 = kendo.template("<div><h1 class='header'><#= data.header #></h1><h2 class='header2'><#= data.header2 #></h2><h3 class='header3'><#= data.header3 #></h3><h4 class='header4'><#= data.header4 #></h4><h5 class='header5'><#= data.header5 #></h5><h6 class='header6'><#= data.header6 #></h6><ul class='list'><# for (var i = 0, l = data.list.length; i < l; i++) { #><li class='item'><#= data.list[i] #></li><# } #></ul></div>", {useWithBlock:false});
  
  //Use external template definition
  window.kendoUIAlt = kendo.template($("#kendoUIextTemplate").html());
  window.kendoUIAlt2 = kendo.template($("#kendoUIextTemplate").html(), {useWithBlock:false});
  
  window.underscoreTemplate = _.template("<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.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>";
  
  //Resig Template Function (modified to support ')
  function tmpl(str) {
              var strFunc =
              "var p=[];" +
                          "with(obj){p.push('" +
  
              str.replace(/[\r\t\n]/g, " ")
                 .replace(/'(?=[^#]*#>)/g, "\t")
                 .split("'").join("\\'")
                 .split("\t").join("'")
                 .replace(/<#=(.+?)#>/g, "',$1,'")
                 .split("<#").join("');")
                 .split("#>").join("p.push('")
                 + "');}return p.join('');";
  
              return new Function("obj", strFunc);
          }
  
  window.resig = tmpl("<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>");
  
  //Resig modified template function (no "with" block)
  function tmpl2(str) {
              var strFunc =
              "var p=[];" +
                          "p.push('" +
  
              str.replace(/[\r\t\n]/g, " ")
                 .replace(/'(?=[^#]*#>)/g, "\t")
                 .split("'").join("\\'")
                 .split("\t").join("'")
                 .replace(/<#=(.+?)#>/g, "',$1,'")
                 .split("<#").join("');")
                 .split("#>").join("p.push('")
                 + "');return p.join('');";
  
              return new Function("data", strFunc);
          }
  
  window.resig2 = tmpl2("<div><h1 class='header'><#= data.header #></h1><h2 class='header2'><#= data.header2 #></h2><h3 class='header3'><#= data.header3 #></h3><h4 class='header4'><#= data.header4 #></h4><h5 class='header5'><#= data.header5 #></h5><h6 class='header6'><#= data.header6 #></h6><ul class='list'><# for (var i = 0, l = data.list.length; i < l; i++) { #><li class='item'><#= data.list[i] #></li><# } #></ul></div>");
</script>
    

Preparation code output

<script src="http://documentcloud.github.com/underscore/underscore.js"></script> <!--NOTE: Need to load from CDNJS since GitHub uses text/plain MIME type, which is blocked in IE9--> <!--<script src="http://github.com/janl/mustache.js/raw/master/mustache.js"></script>--> <script src="http://ajax.cdnjs.com/ajax/libs/mustache.js/0.3.0/mustache.min.js"></script> <script src="https://github.com/downloads/wycats/handlebars.js/handlebars.1.0.0.beta.3.js"></script> <script src="http://cdn.kendostatic.com/2011.2.804/js/kendo.all.min.js"></script> <script src="http://jashkenas.github.com/coffee-script/extras/coffee-script.js"></script> <!--NOTE: Need to load from MSFT CDN since GitHub uses text/plain MIME type, which is blocked in IE9--> <!--<script src="http://github.com/jquery/jquery-tmpl/raw/master/jquery.tmpl.min.js"></script>--> <script src="http://ajax.microsoft.com/ajax/jquery.templates/beta1/jquery.tmpl.min.js"></script> <!--External Template Definitions--> <script type="text/x-kendo-template" id="kendoUIextTemplate"> <div> <h1 class='header'><#= data.header #></h1> <h2 class='header2'><#= data.header2 #></h2> <h3 class='header3'><#= data.header3 #></h3> <h4 class='header4'><#= data.header4 #></h4> <h5 class='header5'><#= data.header5 #></h5> <h6 class='header6'><#= data.header6 #></h6> <ul class='list'> <# for (var i = 0, l = data.list.length; i < l; i++) { #> <li class='item'><#= data.list[i] #></li> <# } #> </ul> </div> </script> <script> 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.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.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.kendouiTemplate = kendo.template("<div><h1 class='header'><#= data.header #></h1><h2 class='header2'><#= data.header2 #></h2><h3 class='header3'><#= data.header3 #></h3><h4 class='header4'><#= data.header4 #></h4><h5 class='header5'><#= data.header5 #></h5><h6 class='header6'><#= data.header6 #></h6><ul class='list'><# for (var i = 0, l = data.list.length; i < l; i++) { #><li class='item'><#= data.list[i] #></li><# } #></ul></div>", {useWithBlock:true}); window.kendouiTemplate2 = kendo.template("<div><h1 class='header'><#= data.header #></h1><h2 class='header2'><#= data.header2 #></h2><h3 class='header3'><#= data.header3 #></h3><h4 class='header4'><#= data.header4 #></h4><h5 class='header5'><#= data.header5 #></h5><h6 class='header6'><#= data.header6 #></h6><ul class='list'><# for (var i = 0, l = data.list.length; i < l; i++) { #><li class='item'><#= data.list[i] #></li><# } #></ul></div>", {useWithBlock:false}); //Use external template definition window.kendoUIAlt = kendo.template($("#kendoUIextTemplate").html()); window.kendoUIAlt2 = kendo.template($("#kendoUIextTemplate").html(), {useWithBlock:false}); window.underscoreTemplate = _.template("<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.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>"; //Resig Template Function (modified to support ') function tmpl(str) { var strFunc = "var p=[];" + "with(obj){p.push('" + str.replace(/[\r\t\n]/g, " ") .replace(/'(?=[^#]*#>)/g, "\t") .split("'").join("\\'") .split("\t").join("'") .replace(/<#=(.+?)#>/g, "',$1,'") .split("<#").join("');") .split("#>").join("p.push('") + "');}return p.join('');"; return new Function("obj", strFunc); } window.resig = tmpl("<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>"); //Resig modified template function (no "with" block) function tmpl2(str) { var strFunc = "var p=[];" + "p.push('" + str.replace(/[\r\t\n]/g, " ") .replace(/'(?=[^#]*#>)/g, "\t") .split("'").join("\\'") .split("\t").join("'") .replace(/<#=(.+?)#>/g, "',$1,'") .split("<#").join("');") .split("#>").join("p.push('") + "');return p.join('');"; return new Function("data", strFunc); } window.resig2 = tmpl2("<div><h1 class='header'><#= data.header #></h1><h2 class='header2'><#= data.header2 #></h2><h3 class='header3'><#= data.header3 #></h3><h4 class='header4'><#= data.header4 #></h4><h5 class='header5'><#= data.header5 #></h5><h6 class='header6'><#= data.header6 #></h6><ul class='list'><# for (var i = 0, l = data.list.length; i < l; i++) { #><li class='item'><#= data.list[i] #></li><# } #></ul></div>"); </script>

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
Mustache.js Template
Mustache.to_html(mustacheTemplate, sharedVariables);
pending…
jQuery Templates
jQueryTemplate($, {
 data: sharedVariables
}).join("");
pending…
Kendo UI Templates (Default)
kendouiTemplate(sharedVariables);
pending…
Kendo UI Templates (No "with" block)
kendouiTemplate2(sharedVariables)
pending…
Kendo UI Templates (External Temp Def)
kendoUIAlt(sharedVariables);
pending…
Kendo UI Templates (External Temp Def - No "with" block))
kendoUIAlt2(sharedVariables);
pending…
Handlebars.js
handlebarsTemplate(sharedVariables);
pending…
Underscore.js Template
underscoreTemplate(sharedVariables);
pending…
Resig Micro Templates (modified)
resig(sharedVariables)
pending…
Resig Micro Templates (No "with" block)
resig2(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.

1 Comment

Eamon Nerbonne commented :

Please don't edit this version, edit version 878 instead - that includes rudimentary output checking so that broken implementations don't distort the results.