jsPerf.app is an online JavaScript performance benchmark test runner & jsperf.com mirror. It is a complete rewrite in homage to the once excellent jsperf.com now with hopefully a more modern & maintainable codebase.
jsperf.com URLs are mirrored at the same path, e.g:
https://jsperf.com/negative-modulo/2
Can be accessed at:
https://jsperf.app/negative-modulo/2
Compared Mustache.js, Handlebars.js, Hogan.js , templayed.js and LT.
Add compile benchmark. Here is another benchmark
<script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/0.7.2/mustache.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/1.0.0/handlebars.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/hogan.js/2.0.0/hogan.js"></script>
<script src="https://archan937.github.io/templayed.js/templayed.js"></script>
<script>
/*!
* LT - Little Template engine of {{mustache}}
* https://github.com/rhyzx/lt
*/
!(function (root, undefined) {
var _isArray = Array.isArray || function(obj) {
return Object.prototype.toString.call(obj) === '[object Array]'
}
// print value
function print(value, escape) {
return typeof value === 'undefined'
? '' // placeholder
: ( escape && /[&"<>]/.test(value += '') )
// escape HTML chars http://www.w3.org/TR/html4/charset.html#h-5.3.2
? value.replace(/&/g, '&').replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>')
: value
}
// get defined value from context stack
function get(scope, depth) {
scope = scope.replace(/^(\.\.\/)+/, function (all, one) {
depth -= all.length / one.length // parent path
return ''
})
if (depth < 0) return "undefined"
if (scope === '.') return "s" +depth // this
var first = scope.match(/^[^.]+/)[0] // nest path support, extract first scope for context finding
var code = ''
while (depth > 0) code += "typeof s" +depth +"." +first +" !== 'undefined' ? s" +depth-- +"." +scope +" : "
return code +"s0." +scope
}
// core
function compile(source) {
var inverted = 0, depth = 0 // context stack depth
var compiled = new Function("s0", "print", "_isArray", "var out = '" +source
.replace(/\\/g, "\\\\") // escape \
.replace(/'/g, "\\'") // escape '
.replace(/\{\{([\^#/!&]?)([^{\n]+?)\}\}/g, function (a, flag, scope) { // block
switch (flag) {
case '^': // if not
inverted++
return "'; var value = " +get(scope, depth)
+ " ; if (!value || (_isArray(value) && value.length === 0)) { out += '"
case '#': // if/each/TODO lambdas/TODO helper
return "'; var value = " +get(scope, depth++)
+ " ; var list = value ? _isArray(value) ? value : [value] : []"
+ " ; for (var i=0, len=list.length; i<len; i++) {"
+ " ; var s" +depth +" = list[i]; out += '"
case '/': // close
inverted > 0 ? inverted-- : depth--
return "'} out += '"
case '!': // comments
return ""
//case '>': // TODO partials
case '&': // print noescape
return "' +print(" +get(scope, depth) +", false) +'"
default : // print escape
return "' +print(" +get(scope, depth) +", true) +'"
}
})
.replace(/\n/g, "\\n") // escape cr
+"'; return out")
var template = function (data) {
return compiled(data, print, _isArray)
}
return template.render = template // render api
}
compile.compile = compile // compile api
// exports
if (typeof module !== 'undefined' && module.exports) {
module.exports = compile // CommonJS
} else if (typeof define === 'function' && define.amd) {
define('lt', compile) // AMD
} else {
root['lt'] = compile // <script>
}
})(this)
</script>
var tests = [{
template: "<p>My name is {{name}}!</p>",
variables: {
name: "Paul Engel"
}
}, {
template: "<p>My name is {{name}}!{{!name}}</p>",
variables: {
name: "Paul Engel"
}
}, {
template: "<p>{{html}} {{&html}}</p>",
variables: {
html: "<strong>Paul Engel</strong>"
}
}, {
template: "<p>{{html}} {{html}}</p>",
variables: {
html: "<strong>Paul Engel</strong>"
}
}, {
template: "<p>This is shown!{{#show}} Psst, this is never shown{{/show}}</p>",
variables: {}
}, {
template: "<p>This is shown!{{#show}} Psst, this is never shown{{/show}}</p>",
variables: {
show: false
}
}, {
template: "<p>This is shown!{{#shown}} And, this is also shown{{/shown}}</p>",
variables: {
shown: true
}
}, {
template: "<p>My name is {{person.first_name}} {{person.last_name}}!</p>",
variables: {
person: {
first_name: "Paul",
last_name: "Engel"
}
}
}, {
template: "{{name}}<ul>{{#names}}<li>{{name}}</li>{{/names}}</ul>{{^names}}Sorry, no people to list!{{/names}}",
variables: {
names: []
}
}, {
template: "<p>{{name}}</p><ul>{{#names}}<li>{{name}}</li>{{/names}}</ul>{{^names}}Sorry, no people to list!{{/names}}<p>{{name}}</p>",
variables: {
name: "Chunk Norris",
names: [{
name: "Paul"
}, {
name: "Engel"
}]
}
}, {
template: "<ul>{{#names}}<li>{{.}}{{foo}}</li>{{/names}}</ul>",
variables: {
names: ["Paul", "Engel"]
}
}, {
template: "<ul>{{#names}}<li>{{fullName}}</li>{{/names}}</ul>",
variables: {
names: [{
firstName: "Paul",
lastName: "Engel"
}, {
firstName: "Chunk",
lastName: "Norris"
}]
// remove lambdas for LT don't support yet(stringify function can consume lots)
}
}];
var compiled = {
"Mustache.js": [],
"Handlebars.js": [],
"Hogan.js": [],
"templayed.js": [],
"lt": []
};
for (var i = 0; i < tests.length; i++) {
var template = tests[i].template;
compiled["Mustache.js"].push(Mustache.compile(template.replace(/\.\.\//g, "")));
var HandlebarsT = Handlebars.compile(template);
HandlebarsT({}); //disable Handlebars' lazy-compile
compiled["Handlebars.js"].push(HandlebarsT);
compiled["Hogan.js"].push(Hogan.compile(template.replace(/\.\.\//g, "")));
compiled["templayed.js"].push(templayed(template));
compiled["lt"].push(lt.compile(template));
}
Ready to run.
Test | Ops/sec | |
---|---|---|
Mustache.js |
| ready |
Handlebars.js |
| ready |
Hogan.js |
| ready |
templayed.js |
| ready |
LT |
| ready |
You can edit these tests or add more tests to this page by appending /edit to the URL.