JavaScript template language shootoff

JavaScript performance comparison

Revision 318 of this test case created by Jens and last updated

Preparation code

<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>
    

Preparation code output

<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

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
Resig Micro Templates (No "with" block)
resig2(sharedVariables);
pending…
Kendo UI Templates (No "with" block)
kendouiTemplate2(sharedVariables);
pending…
Kendo UI Templates (External Temp Def - No "with" block))
kendoUIAlt2(sharedVariables);
pending…
T2 template v2 (Resig+Kendo based)
t2acomp(sharedVariables);
pending…
T2 template v3 (Resig+Kendo, w. loop sugar)
t2bcomp(sharedVariables2);
pending…
T2 template v4 (Resig+Kendo, w. loop sugar, non-recursive)
t2ccomp(sharedVariables2);
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.

0 Comments