Handlebars compile vs precompile

Benchmark created by Carl Lewis on


Description

Handlebars templates are designed so that they may be pre-compiled and cached ahead of time on the server. The intention is to save the client on processing time during page load. The price is that the code must ultimately be delivered as a string.

This test is to determine the exact time and processing savings gained by using a "pre-compiled" function that is delivered to the client from the server versus just compiling the template source in the user's browser.

Handlebars pre-compilation note: Templates that are compiled normally are wrapped up inside of a layer of closures to prevent hacking and attempts by external code and/or helpers into breaking out of the given context. In order to deliver already compiled templates to the client, Handlebars exposes a "precompile" function that returns a native javascript function that must be ran through the so-called virtual machine in order for it to be usable. This process is complicated by server delivery, which may include deferred loading techniques where writing in a native script block for browser parsing is unavailable (ajax).

TESTS: * Normal Compililation: Template source text is ran through the standard compilation which returns a template function * Precomp + Eval + VM: A pre-compiled function string is evaluated into a native function, then converted into a template function (ajax delivery) * Native Precomp + VM: A pre-compiled function is parsed by the browser, then converted into a template function (script embed)

Preparation HTML

console.log("a");

<script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script src="https://github.com/downloads/wycats/handlebars.js/handlebars-1.0.0.beta.6.js"></script>

<!-- template source code -->
<script id="source" type="text/plain">
<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'>{{#each list}}<li class='item'>{{this}}</li>{{/each}}</ul></div>
</script>

<!-- template source that has been pre-compiled into a native function then minified using closure compiler -->
<script>
var nativeprecomp=function(b,c,d,a,e){var d=d||b.helpers,f=d.helperMissing,g=this.escapeExpression,b="<div><h1 class='header'>",a=(a=d.header)||c.header;"function"===typeof a?a=a.call(c,{hash:{}}):void 0===a&&(a=f.call(c,"header",{hash:{}}));b+=g(a)+"</h1><h2 class='header2'>";a=(a=d.header2)||c.header2;"function"===typeof a?a=a.call(c,{hash:{}}):void 0===a&&(a=f.call(c,"header2",{hash:{}}));b+=g(a)+"</h2><h3 class='header3'>";a=(a=d.header3)||c.header3;"function"===typeof a?a=a.call(c,{hash:{}}):void 0===
a&&(a=f.call(c,"header3",{hash:{}}));b+=g(a)+"</h3><h4 class='header4'>";a=(a=d.header4)||c.header4;"function"===typeof a?a=a.call(c,{hash:{}}):void 0===a&&(a=f.call(c,"header4",{hash:{}}));b+=g(a)+"</h4><h5 class='header5'>";a=(a=d.header5)||c.header5;"function"===typeof a?a=a.call(c,{hash:{}}):void 0===a&&(a=f.call(c,"header5",{hash:{}}));b+=g(a)+"</h5><h6 class='header6'>";a=(a=d.header6)||c.header6;"function"===typeof a?a=a.call(c,{hash:{}}):void 0===a&&(a=f.call(c,"header6",{hash:{}}));b+=g(a)+
"</h6><ul class='list'>";a=(a=d.list)||c.list;d=d.each;e=this.program(1,function(a){var c,b;c="<li class='item'>";b=a;"function"===typeof b?b=b.call(a,{hash:{}}):void 0===b&&(b=f.call(a,"this",{hash:{}}));return c+=g(b)+"</li>"},e);e.hash={};e.fn=e;e.inverse=this.noop;if((a=d.call(c,a,e))||0===a)b+=a;return b+"</ul></div>"};
</script>

<script>
//pull the template source into a local variable
var source = $("#source").html();
//simulate server ajax delivery
var precomp = Handlebars.precompile(source).toString(); 

//inline comp method            
window.methoda = function(tpl) {
   return Handlebars.compile(tpl);
};

//precomp method + eval
window.methodb = function(tpl) {
   //eval param
   var func;                    
   eval("func = " + tpl);
   return Handlebars.VM.template(func);
};

//native precomp
window.methodc = function(tpl) {
   return Handlebars.VM.template(tpl);
};
</script>

Test runner

Ready to run.

Testing in
TestOps/sec
Normal Compilation
methoda(source);
ready
Precomp + Eval + VM
methodb(precomp);
ready
Native Precomp + VM
methodc(nativeprecomp);
ready

Revisions

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