Why you should update your Mustache.js

If your mustache template renders in more then 2-5s on iPad or iPhone and you want to bring that number down to 30ms, have a quick read :)

Background

After profiling one web application I've found some worying JS performance issues on mobile devices. Some of the big templates ware taking more than 4, 5 or even 10 sekonds to render!! To make things more fun, only i-devices ware effected.

Short investigation revield that squashTokens is taking 99% of that time. Turned out that array splice is really slow. Here's the original function:

function squashTokens(tokens) {
  var lastToken;

  for (var i = 0; i < tokens.length; ++i) {
    var token = tokens[i];

    if (lastToken && lastToken.type === "text" && token.type === "text") {
      lastToken.value += token.value;
      tokens.splice(i--, 1); // Remove this token from the array.
    } else {
      lastToken = token;
    }
  }
}

The fix was simple - instead of manipulating original array, let's build new one! Simple idea, even simpler implementation.

function squashTokens(tokens) {
  var token, lastToken, squashedTokens = [];

  for (var i = 0; i < tokens.length; ++i) {
    token = tokens[i];

    if (lastToken && lastToken.type === "text" && token.type === "text") {
      lastToken.value += token.value;
    } else {
      lastToken = token;
      squashedTokens.push(token);
    }
  }

  return squashedTokens; 
}

Why V8 was so Fast

Why mustache runs so fast on V8?
I'm not sure if that's true or not, but apparently splice(index, 1) was optimized and runs arround x100 faster then for instance splice(index, 2) - that's something I need to test :)
It's simply because V8 is amazing.

What Next?

I will try to setup browserscope speed tests for mustache.js.

Testing The Fix

I did some testing today (9 Nov 2012) on various mobile devices. You can check the test template in the source of this page or just run $('#tpl').html() in JS console. Data for template is very small and simple. And here are some interesting numbers:

| Device           | OS        | avg time v-0.7.0 | avg time v-master |
+------------------+-----------+------------------+-------------------+
| ipad2            | iOS 5.1.1 | 4142             | 33                |
| ipad3            | iOS 6.0.0 | 5037             | 34                |
| iphone 5         | iOS 6.0.1 | 3428             | 20                |
| iphone 3GS       | iOS 4.3   | 7925             | 128               |
| experia mini pro | A 2.3.4   | 124              | 95                |
| samsung GT-l9300 | A 4.1.1   | 57               | 30                |
| asus TF101       | A 4.0.3   | 44               | 23                |

If you want, you can run these tests in your browser, simply click bellow buttons (links) and check numbers.

Mustache 0.7.0 Test

total time in ms  output length
avg:

Mustache master branch Test

total time in ms  output length
avg:

Mustache 0.5.0-dev Test

total time in ms  output length
avg:

JS function used in test.

function benchmark(m) {

        m.clearCache();

        var tic = new Date().getTime();
        var r = m.render(tpl, tplData)
        var toc = new Date().getTime();
}