JSTemplates
JavaScript performance comparison
Preparation code
<script src="https://github.com/olado/doT/raw/master/doT.js"></script>
<script>
( function() {
var _innerText = 'textContent';
// using cc to target execution only for IE
/*@cc_on
@if ( @_jscript )
_innerText = 'innerText';
@end
@*/
function children( dom ) {
var childs = dom.children || dom.childNodes,
childs_out = [];
for( var i=0, l=childs.length; i<l; i++ )
if( childs[i].nodeType === 1 )
childs_out.push(childs[i]);
return childs_out;
}
var templateJS = function() {
// templates cache
var templates = [];
return {
getTemplate: function( id, kill ) {
// template node
var dom;
// get node by #ID
if( typeof id === 'string' )
dom = document.getElementById( id );
// get node by DOM-Element
else if( id.nodeValue && id.nodeType )
dom = id;
// break if no valid node given
if( !dom )
return;
// traverse template node
// IMPORTANT - give a cloned node
dom = dom.cloneNode(true);
// create template
var tmpl = {
dom: dom
},
children_stack = [ children( dom ) ], // Child STACK
k = 0, // STACK counter
// current STACK values
childs = children_stack[k],
i = [0],
l = [childs.length],
// curent STACK children counters
j = i[k],
n = l[k],
has_children,
current_dom,
shortcuts = {}, // this shortcuts will be available
shortcut_attr = "data-tmpl",
shortcut_name,
stack_switched = false; // indicates that STACK has been switched
// check shortcut for root node
shortcut_name = dom.getAttribute(shortcut_attr);
if(shortcut_name)
shortcuts[shortcut_name] = dom;
// traverse all children of template
for(; j < n;) {
current_dom = childs[j];
// create shortcut
shortcut_name = current_dom.getAttribute(shortcut_attr);
if(shortcut_name)
shortcuts[shortcut_name] = current_dom;
has_children = children( current_dom );
// create new child object
if( has_children.length ) {
// increase STACKS
children_stack.push( has_children );
i.push(0);
l.push( has_children.length );
// save last STACK children counter
i[k] = j+1;
++k;
stack_switched = true;
} else {
j++;
// if last children go up
if( k > 0 && j === n ) {
delete children_stack[k];
delete i[k];
delete l[k];
--k;
stack_switched = true;
}
}
// checkout switched stack data
if( stack_switched ) {
childs = children_stack[k];
j = i[k];
n = l[k];
stack_switched = false;
}
}
// add childrens to template
tmpl.shortcuts = shortcuts;
// push template to cache
templates.push( tmpl );
// delete template source after traversing
if( kill )
dom.parentNode.removeChild( dom );
return templates.length - 1;
},
// delete existing template
killTemplate: function( id ) {
if( templates[tmpl] )
delete templates[tmpl];
return this;
},
// render existing template
render: function( id, obj ) {
if( !templates[id] ) return;
var data = obj.data,
keys = obj.keys,
tmpl = templates[id],
tmpl_shortcuts = tmpl.shortcuts,
fragment = document.createDocumentFragment(),
obj,
shortcut_key,
shortcut_dom,
shortcut_obj,
key;
for( var i=0, l=data.length; i<l; i++ ) {
obj = data[i];
for( var x=0, n=keys.length; x<n; x++ ) {
shortcut_key = keys[x];
shortcut_dom = tmpl_shortcuts[ shortcut_key ];
shortcut_obj = obj[ shortcut_key ];
for( key in shortcut_obj ) {
if( key == 'text' )
shortcut_dom[_innerText] = shortcut_obj[key];
else if( typeof shortcut_dom[key] !== 'undefined' )
shortcut_dom[key] = shortcut_obj[key];
else
shortcut_dom.setAttribute( key, shortcut_obj[key] );
}
}
fragment.appendChild( tmpl.dom.cloneNode(true) );
}
return fragment;
}
};
}();
window.templateJS = window.$t = templateJS;
}());
</script>
<li id="li-template" class="li" data-tmpl="li">
<a class="click" target="_self" href="" data-tmpl="link">
<img class="thumb" src="void:javascript(0)" data-tmpl="img">
<div class="info">
<h3 class="title" data-tmpl="title"></h3>
<p class="desc" data-tmpl="desc"></p>
<em class="misc" data-tmpl="misc"></em>
</div>
<em class="date" data-tmpl="date"></em>
<em class="price" data-tmpl="price"></em>
</a>
</li>
<ol id="li-box">
</ol>
<script>
Benchmark.prototype.setup = function() {
var box = document.getElementById('li-box'),
t = $t.getTemplate("li-template");
window.doTtemplate = doT.template('{{ for (var i = 0, l = it.data.length; i < l; i++) { }}<li class="item">{{= it.data[i] }}</li><li id="{{= it.data[i].li.id }}" class="li"><a class="click" target="_self" href="{{= it.data[i].link.href }}"><img class="thumb" src="{{= it.data[i].img.src }}"><div class="info"><h3 class="title">{{= it.data[i].title.text }}</h3><p class="desc">{{= it.data[i].desc.text }}</p><em class="misc">{{= it.data[i].misc.text }}</em></div><em class="date">{{= it.data[i].date.text }}</em><em class="price">{{= it.data[i].price.text }}</em></a></li>{{ } }}');
var shortcut_list = {
keys:['li','link','img','title','desc','misc','date','price'],
data: [
{
li: { id:1 },
link: { href: "http://www.tutti.ch" },
img: { src: "http://lorempixel.com/200/100" },
title: { text:"Titel 1" },
desc: { text:"Beschreibung 1" },
misc: { text:"Canton/Kategorie 1" },
date: { text:"Datum 1" },
price: { text:"Preis 1" }
},
{
li: { id:2 },
link: { href: "http://www.tutti.ch" },
img: { src: "http://lorempixel.com/200/100" },
title: { text:"Titel 2" },
desc: { text:"Beschreibung 2" },
misc: { text:"Canton/Kategorie 2" },
date: { text:"Datum 2" },
price: { text:"Preis 2" }
},
{
li: { id:3 },
link: { href: "http://www.tutti.ch" },
img: { src: "http://lorempixel.com/200/100" },
title: { text:"Titel 3" },
desc: { text:"Beschreibung 3" },
misc: { text:"Canton/Kategorie 3" },
date: { text:"Datum 3" },
price: { text:"Preis 3" }
},
{
li: { id:4 },
link: { href: "http://www.tutti.ch" },
img: { src: "http://lorempixel.com/200/100" },
title: { text:"Titel 4" },
desc: { text:"Beschreibung 4" },
misc: { text:"Canton/Kategorie 4" },
date: { text:"Datum 4" },
price: { text:"Preis 4" }
},
{
li: { id:5 },
link: { href: "http://www.tutti.ch" },
img: { src: "http://lorempixel.com/200/100" },
title: { text:"Titel 5" },
desc: { text:"Beschreibung 5" },
misc: { text:"Canton/Kategorie 5" },
date: { text:"Datum 5" },
price: { text:"Preis 5" }
},
{
li: { id:6 },
link: { href: "http://www.tutti.ch" },
img: { src: "http://lorempixel.com/200/100" },
title: { text:"Titel 6" },
desc: { text:"Beschreibung 6" },
misc: { text:"Canton/Kategorie 6" },
date: { text:"Datum 6" },
price: { text:"Preis 6" }
},
{
li: { id:7 },
link: { href: "http://www.tutti.ch" },
img: { src: "http://lorempixel.com/200/100" },
title: { text:"Titel 7" },
desc: { text:"Beschreibung 7" },
misc: { text:"Canton/Kategorie 7" },
date: { text:"Datum 7" },
price: { text:"Preis 7" }
},
{
li: { id:8 },
link: { href: "http://www.tutti.ch" },
img: { src: "http://lorempixel.com/200/100" },
title: { text:"Titel 8" },
desc: { text:"Beschreibung 8" },
misc: { text:"Canton/Kategorie 8" },
date: { text:"Datum 8" },
price: { text:"Preis 8" }
}
]
};
};
</script>
Preparation code output
Test runner
Warning! For accurate results, please disable Firebug before running the tests. (Why?)
Java applet disabled.
| Test | Ops/sec | |
|---|---|---|
my own |
|
pending… |
doT |
|
pending… |
compile my own |
|
pending… |
compile doT |
|
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:
- Revision 1: published by Andreas Deuschlinger
- Revision 2: published by Andreas Deuschlinger
- Revision 3: published by Andreas Deuschlinger
- Revision 4: published by Andreas Deuschlinger
0 comments