12. Views - Templating

What’s in a template?

I would classify templating systems not based on their input, but based on their output:

The simplest systems make string interpolation and array iteration more convinient. The more complex ones generate metadata that can be used as an input for other systems.

The simplest templating system

A template is the part of the view object that is responsible for generating HTML from input data. In other words, a template is a function which takes a single argument: base (context) and returns a string of HTML.

function itemTemplate(base) {
  return [
    '<li>',
      '<div class="todo', (base.done ? ' done' : ''), '">', base.text, '</div>',
    '</li>'
  ].join('');
}

Of course, writing templates with this syntax is generally not preferred. Instead, templating libraries are used in order to get the best of both worlds: the nicest possible template definition syntax; and the performance of using native JS operations. Templating syntax should have no performance impact - you should always precompile your templates into their optimal JS equivalents.

The optimal output for simple templates

In theory, unless a templating library does something extremely unusual, all of the templating libraries should have similar performance: after all, they only perform string interpolation on an input and ought to compile to similar compiled JS output.

Sadly, in the real world very few templating languages actually compile to the optimal markup. Have a look at the results from this benchmark:

Resig Micro-templating:
3,813,204
(3813 templates per ms; 61,008 in 16ms)
Underscore.js template:
76,012
(76 templates per ms; 1216 in 16ms)
Handlebars.js:
45,953
(46 templates per ms; 736 in 16ms)
ejs:
14,927
(15 templates per ms; 240 in 16ms)

I’m not discussing the causes here, because even with the slowest templating engine, the rendering itself doesn’t have a significant impact in terms of total time (since even the slowest engines can cope with hundreds of template renders per 16 ms). In other words - despite large differences (up to two orders of magnitude) in microbenchmarks - generating HTML from a compiled template is unlikely to be a bottleneck no matter how slow it is, except on mobile browsers.

Outputting metadata / objects with lifecycles

As I noted in the overview chapter for the view layer, the key difference between view layer implementations is their update granularity: whether views are redrawn as a whole (view-granular) or can be rendered at element-granularity or string-granularity.

View-granular systems can just use the simple output where a compiled template is represented as a function that takes a set of data and returns a string. Element-granular and string-granular view layers need more metadata, because they need to convert the bindings into code that keeps track of and updates the right parts of the view.

Hence, element-granular and string-granular rendering requires a templating system that outputs objects / metadata in addition to strings. Notice that this doesn’t generally affect what features are supported in the templating language: it just affects how granular the updates are and the syntax for defining things like event handlers.