Mustache JS templates

JavaScript performance comparison

Revision 2 of this test case created by Joshua Peek

Info

Interpreted vs compiled Mustache template functions.

Preparation code

<script src="http://mustache.github.com/extras/mustache.js"></script>

<script>
  window.interpretedTemplate = "<div><h1 class='header'>{{header}}</h1><div class='a'>{{a}}</div><div class='b'>{{b}}<div class='c'>{{c}}<div class='d'>{{d}}<div class='e'>{{e}}<div class='f'>{{f}}</div></div></div></div></div></div>";
 
  window.compiledTemplate = function(obj) {
   var out, l1, l2, l3, l4, l5, l6, l7, stack, fetch, escape, isFunction;
   out = [];
   stack = [];
   stack.push(obj);
   fetch = function fetch(key) {
    var i, v;
    for (i = stack.length - 1; i >= 0; i -= 1) {
     v = stack[i][key];
     if (v) {
      return v;
     }
    }
   };
   escape = function escape(value) {
    return ('' + value).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
   };
   isFunction = function isFunction(obj) {
    return !!(obj && obj.constructor && obj.call && obj.apply);
   };
 
   out.push("<div><h1 class='header'>");
   l1 = fetch("header");
   if (isFunction(l1)) {
    l1 = l1.call(stack[stack.length - 1]);
   }
   out.push(escape(l1));
   out.push("</h1><div class='a'>");
   l2 = fetch("a");
   if (isFunction(l2)) {
    l2 = l2.call(stack[stack.length - 1]);
   }
   out.push(escape(l2));
   out.push("</div><div class='b'>");
   l3 = fetch("b");
   if (isFunction(l3)) {
    l3 = l3.call(stack[stack.length - 1]);
   }
   out.push(escape(l3));
   out.push("<div class='c'>");
   l4 = fetch("c");
   if (isFunction(l4)) {
    l4 = l4.call(stack[stack.length - 1]);
   }
   out.push(escape(l4));
   out.push("<div class='d'>");
   l5 = fetch("d");
   if (isFunction(l5)) {
    l5 = l5.call(stack[stack.length - 1]);
   }
   out.push(escape(l5));
   out.push("<div class='e'>");
   l6 = fetch("e");
   if (isFunction(l6)) {
    l6 = l6.call(stack[stack.length - 1]);
   }
   out.push(escape(l6));
   out.push("<div class='f'>");
   l7 = fetch("f");
   if (isFunction(l7)) {
    l7 = l7.call(stack[stack.length - 1]);
   }
   out.push(escape(l7));
   out.push("</div></div></div></div></div></div>");
   return out.join("");
  };
 
  window.optimizedCompiledTemplate = (function() {
   var g1, g2, g2, fetch, escape, isEmpty, isArray, isObject, isFunction;
   fetch = function fetch(stack, key) {
    var i, v;
    for (i = stack.length - 1; i >= 0; i -= 1) {
     v = stack[i][key];
     if (v) {
      return v;
     }
    }
   };
   escape = function escape(value) {
    return ('' + value).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
   };
   isEmpty = function isEmpty(obj) {
    var key;
 
    if (!obj) {
     return true;
    } else if (isArray(obj)) {
     return obj.length === 0;
    } else if (isObject(obj)) {
     for (key in obj) {
      if (obj.hasOwnProperty(key)) {
       return false;
      }
     }
     return true;
    } else {
     return false;
    }
   };
   isArray = Array.isArray ||
   function isArray(obj) {
    return Object.prototype.toString.call(obj) === '[object Array]';
   };
   isObject = function isObject(obj) {
    return (obj && typeof obj === 'object');
   };
   isFunction = function isFunction(obj) {
    return !!(obj && obj.constructor && obj.call && obj.apply);
   };
   g2 = function g2(stack, out) {
    var l3, l4, l5, l6, l7, l8, l9;
 
    out.push("<div><h1 class='header'>");
    l3 = fetch(stack, "header");
    if (isFunction(l3)) {
     l3 = l3.call(stack[stack.length - 1]);
    }
    if (!isEmpty(l3)) {
     out.push(escape(l3));
    }
    out.push("</h1><div class='a'>");
    l4 = fetch(stack, "a");
    if (isFunction(l4)) {
     l4 = l4.call(stack[stack.length - 1]);
    }
    if (!isEmpty(l4)) {
     out.push(escape(l4));
    }
    out.push("</div><div class='b'>");
    l5 = fetch(stack, "b");
    if (isFunction(l5)) {
     l5 = l5.call(stack[stack.length - 1]);
    }
    if (!isEmpty(l5)) {
     out.push(escape(l5));
    }
    out.push("<div class='c'>");
    l6 = fetch(stack, "c");
    if (isFunction(l6)) {
     l6 = l6.call(stack[stack.length - 1]);
    }
    if (!isEmpty(l6)) {
     out.push(escape(l6));
    }
    out.push("<div class='d'>");
    l7 = fetch(stack, "d");
    if (isFunction(l7)) {
     l7 = l7.call(stack[stack.length - 1]);
    }
    if (!isEmpty(l7)) {
     out.push(escape(l7));
    }
    out.push("<div class='e'>");
    l8 = fetch(stack, "e");
    if (isFunction(l8)) {
     l8 = l8.call(stack[stack.length - 1]);
    }
    if (!isEmpty(l8)) {
     out.push(escape(l8));
    }
    out.push("<div class='f'>");
    l9 = fetch(stack, "f");
    if (isFunction(l9)) {
     l9 = l9.call(stack[stack.length - 1]);
    }
    if (!isEmpty(l9)) {
     out.push(escape(l9));
    }
    out.push("</div></div></div></div></div></div>");
 
   };
 
   return function g1(obj) {
    var stack, out;
    stack = [];
    stack.push(obj);
    out = [];
    g2(stack, out);
    return out.join("");
   };
  })();
 
  window.sharedVariables = {
   header: "Header",
   a: 'aaa',
   b: 'bbb',
   c: 'ccc',
   d: 'ddd',
   e: 'eee',
   f: 'fff'
  };
</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
mustache.js (interpreted)
Mustache.to_html(interpretedTemplate, sharedVariables);
pending…
mustache trimmer (compiled)
compiledTemplate(sharedVariables);
pending…
mustache trimmer (compiled, optimized)
optimizedCompiledTemplate(sharedVariables);
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