JavaScript template language shootoff (v318)

Revision 318 of this benchmark created by Jens on


Description

A comparison of some JavaScript templating engines:

Preparation HTML

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

<script src="http://cdn.kendostatic.com/2011.2.804/js/kendo.all.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.sharedVariables2 = {
   header: "Header",
   header2: "Header2",
   header3: "Header3",
   header4: "Header4",
   header5: "Header5",
   header6: "Header6",
   listitem: [{i:'1'}, {i:'2'}, {i:'3'}, {i:'4'}, {i:'5'}, {i:'6'}, {i:'7'}, {i:'8'}, {i:'9'}, {i:'10'}]
};

  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.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 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>");



function t2a(str) {
    var strFunc = "var p='';p+='" +

        str.replace(/'(?=[^#]*#\})/g, "\t")
        .split("'").join("\\'")
        .split("\t").join("'")
        .replace(/\{=(.+?)\}/g, "'+$1+'")
        .split("{#").join("';")
        .split("#}").join("p+='")
        + "';return p;";

    return new Function("data", strFunc);
}

window.t2acomp = t2a("<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>");






window.T2T = (function(){

        var t2c_array = function(id,tmpls) {
                var str = tmpls[id],
                    index = '_'+id.replace('.','_'),
                    strFunc = "';for (var "+index+"=0; "+index+"<data."+id+".length; "+index+"++) {p+='" +

        str.replace(/[\r\t\n]/g, " ")
        .replace(/'(?=[^#]*#\})/g, "\t")
        .split("'").join("\\'")
        .split("\t").join("'")
        .replace(/\{=@(.+?)\}/g, function(a,b){ return t2c_array(b,tmpls); })
        .replace(/\{=(.+?)\}/g, "'+data."+id+"["+index+"].$1+'")
        .split("{#").join("';")
        .split("#}").join("p+='")
        + "';}p+='";
    return strFunc;
  };

        var exports = {};

        exports.t2b = function(str) {
    var strFunc = "var p='';p+='" +

        str.replace(/'(?=[^#]*#\})/g, "\t")
        .split("'").join("\\'")
        .split("\t").join("'")
        .replace(/\{=@(.+?)\}/g, "'+arguments.callee.cache.$1(data.$1)+'")
        .replace(/\{=(.+?)\}/g, "'+data.$1+'")
        .split("{#").join("';")
        .split("#}").join("p+='")
        + "';return p;";

    return new Function("data", strFunc);
  };

        exports.t2b_array = function(str) {
    var strFunc = "var p='';for (var idx=0; idx<data.length; idx++) {p+='" +

        str.replace(/'(?=[^#]*#\})/g, "\t")
        .split("'").join("\\'")
        .split("\t").join("'")
        .replace(/\{=@(.+?)\}/g, "'+arguments.callee.cache.$1(data.$1)+'")
        .replace(/\{=(.+?)\}/g, "'+data[idx].$1+'")
        .split("{#").join("';")
        .split("#}").join("p+='")
        + "'};return p;";

    return new Function("data", strFunc);
  };

  exports.t2b_all = function(obj) {
          var cache={};
          for(var o in obj) {
                // prepare a compiled template generator for each template
                cache[o] = (o=='$') ? exports.t2b(obj[o]) : exports.t2b_array(obj[o]);
                // attach the generator cache to the function
                cache[o].cache = cache;
          }
          return cache.$;
  }

        exports.t2c = function(tmpls) {
    var str = tmpls['$'],
        strFunc = "var p='';p+='" +

        str.replace(/[\r\t\n]/g, " ")
        .replace(/'(?=[^#]*#\})/g, "\t")
        .split("'").join("\\'")
        .split("\t").join("'")
        .replace(/\{=@(.+?)\}/g, function(a,b){ return t2c_array(b,tmpls); })
        .replace(/\{=(.+?)\}/g, "'+data.$1+'")
        .split("{#").join("';")
        .split("#}").join("p+='")
        + "';return p;";

    return new Function("data", strFunc);
  };

        return exports;
})();



window.t2bcomp = T2T.t2b_all({
$:"<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'>{=@listitem}</ul></div>",
listitem: "<li class='item'>{=i}</li>"
});



window.t2ccomp = T2T.t2c({
$:"<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'>{=@listitem}</ul></div>",
listitem: "<li class='item'>{=i}</li>"
});


</script>

Test runner

Ready to run.

Testing in
TestOps/sec
Resig Micro Templates (No "with" block)
resig2(sharedVariables);
ready
Kendo UI Templates (No "with" block)
kendouiTemplate2(sharedVariables);
ready
Kendo UI Templates (External Temp Def - No "with" block))
kendoUIAlt2(sharedVariables);
ready
T2 template v2 (Resig+Kendo based)
t2acomp(sharedVariables);
ready
T2 template v3 (Resig+Kendo, w. loop sugar)
t2bcomp(sharedVariables2);
ready
T2 template v4 (Resig+Kendo, w. loop sugar, non-recursive)
t2ccomp(sharedVariables2);
ready

Revisions

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