jsPerf.app is an online JavaScript performance benchmark test runner & jsperf.com mirror. It is a complete rewrite in homage to the once excellent jsperf.com now with hopefully a more modern & maintainable codebase.
jsperf.com URLs are mirrored at the same path, e.g:
https://jsperf.com/negative-modulo/2
Can be accessed at:
https://jsperf.app/negative-modulo/2
A comparison of some JavaScript templating engines:
<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>
Ready to run.
Test | Ops/sec | |
---|---|---|
Resig Micro Templates (No "with" block) |
| ready |
Kendo UI Templates (No "with" block) |
| ready |
Kendo UI Templates (External Temp Def - No "with" block)) |
| ready |
T2 template v2 (Resig+Kendo based) |
| ready |
T2 template v3 (Resig+Kendo, w. loop sugar) |
| ready |
T2 template v4 (Resig+Kendo, w. loop sugar, non-recursive) |
| ready |
You can edit these tests or add more tests to this page by appending /edit to the URL.