Fast Template JS engine rumble: Riot.js vs Templayed.js vs doT.js

JavaScript performance comparison

Revision 42 of this test case created by fasdf

Info

Compares Riot.js, templayed.js and doT.js.

Preparation code

<script src="https://raw.github.com/archan937/templayed.js/master/src/templayed.js"></script>
<script>
/* Riot 1.0.0, @license MIT, (c) 2014 Muut Inc + contributors */
(function(e){"use strict";e.observable=function(e){var t={},n=[].slice;e.on=function(n,r){if(typeof r==="function"){n.replace(/[^\s]+/g,function(e,n){(t[e]=t[e]||[]).push(r);r.typed=n>0})}return e};e.off=function(n){n.replace(/[^\s]+/g,function(e){t[e]=[]});if(n=="*")t={};return e};e.one=function(t,n){if(n)n.one=true;return e.on(t,n)};e.trigger=function(r){var o=n.call(arguments,1),u=t[r]||[];for(var i=0,f;f=u[i];++i){if(!f.busy){f.busy=true;f.apply(e,f.typed?[r].concat(o):o);if(f.one){u.splice(i,1);i--}f.busy=false}}return e};return e};var t={},n={"\\":"\\\\","\n":"\\n","\r":"\\r","'":"\\'"},r={"&":"&amp;",'"':"&quot;","<":"&lt;",">":"&gt;"};function o(e,t){return e==undefined?"":(e+"").replace(/[&\"<>]/g,function(e){return r[e]})}e.render=function(e,r,u){if(u===true)u=o;e=e||"";return(t[e]=t[e]||new Function("_","e","try { return '"+e.replace(/[\\\n\r']/g,function(e){return n[e]}).replace(/{\s*([\w\.]+)\s*}/g,"' + (e?e(_.$1,'$1'):_.$1||(_.$1==undefined?'':_.$1)) + '")+"' } catch(e) { return '' }"))(r,u)};if(typeof top!="object")return;var u,i=e.observable({}),f=window.addEventListener,c=document;function a(e){e=e.type?location.hash:e;if(e!=u)i.trigger("pop",e);u=e}if(f){f("popstate",a,false);c.addEventListener("DOMContentLoaded",a,false)}else{c.attachEvent("onreadystatechange",function(){if(c.readyState==="complete")a("")})}e.route=function(e){if(typeof e==="function")return i.on("pop",e);if(history.pushState)history.pushState(0,0,e);a(e)}})(typeof top=="object"?window.riot={}:exports);
// doT
(function(){function o(){var a={"&":"&#38;","<":"&#60;",">":"&#62;",'"':"&#34;","'":"&#39;","/":"&#47;"},b=/&(?!#?\w+;)|<|>|"|'|\//g;return function(){return this?this.replace(b,function(c){return a[c]||c}):this}}function p(a,b,c){return(typeof b==="string"?b:b.toString()).replace(a.define||i,function(l,e,f,g){if(e.indexOf("def.")===0)e=e.substring(4);if(!(e in c))if(f===":"){a.defineParams&&g.replace(a.defineParams,function(n,h,d){c[e]={arg:h,text:d}});e in c||(c[e]=g)}else(new Function("def","def['"+
e+"']="+g))(c);return""}).replace(a.use||i,function(l,e){if(a.useParams)e=e.replace(a.useParams,function(g,n,h,d){if(c[h]&&c[h].arg&&d){g=(h+":"+d).replace(/'|\\/g,"_");c.__exp=c.__exp||{};c.__exp[g]=c[h].text.replace(RegExp("(^|[^\\w$])"+c[h].arg+"([^\\w$])","g"),"$1"+d+"$2");return n+"def.__exp['"+g+"']"}});var f=(new Function("def","return "+e))(c);return f?p(a,f,c):f})}function m(a){return a.replace(/\\('|\\)/g,"$1").replace(/[\r\t\n]/g," ")}var j={version:"1.0.1",templateSettings:{evaluate:/\{\{([\s\S]+?(\}?)+)\}\}/g,
interpolate:/\{\{=([\s\S]+?)\}\}/g,encode:/\{\{!([\s\S]+?)\}\}/g,use:/\{\{#([\s\S]+?)\}\}/g,useParams:/(^|[^\w$])def(?:\.|\[[\'\"])([\w$\.]+)(?:[\'\"]\])?\s*\:\s*([\w$\.]+|\"[^\"]+\"|\'[^\']+\'|\{[^\}]+\})/g,define:/\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g,defineParams:/^\s*([\w$]+):([\s\S]+)/,conditional:/\{\{\?(\?)?\s*([\s\S]*?)\s*\}\}/g,iterate:/\{\{~\s*(?:\}\}|([\s\S]+?)\s*\:\s*([\w$]+)\s*(?:\:\s*([\w$]+))?\s*\}\})/g,varname:"it",strip:true,append:true,selfcontained:false},template:undefined,
compile:undefined},q;if(typeof module!=="undefined"&&module.exports)module.exports=j;else if(typeof define==="function"&&define.amd)define(function(){return j});else{q=function(){return this||(0,eval)("this")}();q.doT=j}String.prototype.encodeHTML=o();var r={append:{start:"'
+(",end:")+'",endencode:"||'').toString().encodeHTML()+'"},split:{start:"';out+=(",end:");out+='",endencode:"||'').toString().encodeHTML();out+='"}},i=/$^/;j.template=function(a,b,c){b=b||j.templateSettings;var l=b.append?r.append:
r.split,e,f=0,g;a=b.use||b.define?p(b,a,c||{}):a;a=("var out='
"+(b.strip?a.replace(/(^|\r|\n)\t* +| +\t*(\r|\n|$)/g," ").replace(/\r|\n|\t|\/\*[\s\S]*?\*\//g,""):a).replace(/'|\\/g,"\\$&").replace(b.interpolate||i,function(h,d){return l.start+m(d)+l.end}).replace(b.encode||i,function(h,d){e=true;return l.start+m(d)+l.endencode}).replace(b.conditional||i,function(h,d,k){return d?k?"';}else if("+m(k)+"){out+='":"';}else{out+='":k?"';if("+m(k)+"){out+='":"';}out+='"}).replace(b.iterate||i,function(h,
d,k,s){if(!d)return"
';} } out+='";f+=1;g=s||"i"+f;d=m(d);return"';var arr"+f+"="+d+";if(arr"+f+"){var "+k+","+g+"=-1,l"+f+"=arr"+f+".length-1;while("+g+"<l"+f+"){"+k+"=arr"+f+"["+g+"+=1];out+='"}).replace(b.evaluate||i,function(h,d){return"';"+m(d)+"out+='"})+"';return out;").replace(/\n/g,"\\n").replace(/\t/g,"\\t").replace(/\r/g,"\\r").replace(/(\s|;|\}|^|\{)out\+='';/g,"$1").replace(/\+''/g,"").replace(/(\s|;|\}|^|\{)out\+=''\+/g,"$1out+=");if(e&&b.selfcontained)a="String.prototype.encodeHTML=("+
o.toString()+"());"+a;try{return new Function(b.varname,a)}catch(n){typeof console!=="undefined"&&console.log("Could not create a template function: "+a);throw n;}};j.compile=function(a,b){return j.template(a,null,b)}})();
</script>
<script>
Benchmark.prototype.setup = function() {
    var tests = [{
      template: "<p>My name is {{name}}!</p>",
      variables: {
        name: "Paul Engel"
      }
    },  {
      template: "<p>{{html}}</p>",
      variables: {
        html: "<strong>Paul Engel</strong>"
      }
    }, {
      template: "<p>My name is {{person.first_name}} {{person.last_name}}!</p>",
      variables: {
        person: {
          first_name: "Paul",
          last_name: "Engel"
        }
      }
    }]
    var templates = {
      "riot.js": [],
      "templayed.js": [],
      "doT.js": []
    }
    for (var i = 0; i < tests.length; i++) {
      var compiled = tests[i].template
      templates["riot.js"].push(template.replace(/({[^{}]+})/g, "$1"))
      templates["templayed.js"].push(template)
      templates["doT.js"].push(template.replace(/{{/g, "{{=it."))
    }
};
</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
riot.js
for (var i = 0; i < tests.length; i++) {
  riot.render(templates["riot.js"][i], tests[i].variables);
}
pending…
templayed.js
for (var i = 0; i < tests.length; i++) {
var template = tests[i].template;
  compiled["templayed.js" ].push(templayed(template));
}
pending…
doT.js
for (var i = 0; i < tests.length; i++) {
  doT.template(templates["doT.js"][i])(tests[i].variables);
}
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:

0 comments

Add a comment