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
This is a simple rendering speed test between the most popular libraries/frameworks.
31.07.2015 Fixing angular Switched track by $index to track by item (track by $index on an array is useless since it never changes) Set jquery version for angular to jq lite
25.07.2015 Updates vuejs, emberjs
18.06.2015 Changed angular "track by item" back to "track by $index". It's faster and more comparable to the rest. Also updated emberjs to latest official release. In the next tests the 2.0.0 branch might want to be tested.
16.06.2015 Apply angular on every write, it's not a remotely representative comparison if angular does its binding 100 times less than every other framework. Stop mithril redrawing twice on every iteration.
06.06.2015 - Using "$track by" for angular, for better performance
31.05.2015 - Updated ember.js to latest beta version
27.05.2015 - Second update today: Changed Angular.js to only $apply ONCE per 100 writes: That's a more realistic comparison to the newer frameworks that do that implicitly. Angular is still disappointingly slow, but what can you do.
27.05.2015 - Fixed 622 on IE. Now Mag.js is super-fast on IE as well, though it performs rather pitifully on mobile. Also, note on React: It looks like the "proper" way to use React is to queue up a bunch of changes and then create them all at once. See this benchmark for an example: https://www.codementor.io/reactjs/tutorial/reactjs-vs-angular-js-performance-comparison-knockout
26.05.2015 - Added Mag.js back to 619 because it's SO fast, even when I force a render in every test, and because it's one of the few that doesn't rely on mixing code into your HTML; 620/621 both fail for me, and 619 was the last version that worked.
17.05.2015 - Updated angular, ember, react and mithril to their latest versions. e.g. ember now uses the new Glimmer engine. However react still is way too slow. I'm not a react expert, please look at react and fix the test if you are experienced with reactjs Also we might want to include ractive and Mercury again, the latest working version seems to be commit 603. However after that it stopped working, therefore it is not included anymore. Feel free to make it work again!
<!-- Jquery -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.3.0/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/1.3.0/handlebars.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ember.js/1.13.4/ember-template-compiler.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ember.js/1.13.4/ember.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.13.3/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mithril/0.2.0/mithril.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/0.12.7/vue.min.js"></script>
<!--[if IE]><script src="https://rawgit.com/jakearchibald/es6-promise/master/dist/es6-promise.min.js"></script><![endif]-->
<script src="https://rawgit.com/magnumjs/mag.js/master/dist/mag.0.11.9.min.js"></script>
<script src="https://cdn.rawgit.com/MaxArt2501/object-observe/master/dist/object-observe.min.js"></script>
<script src="https://rawgit.com/magnumjs/mag.js/master/src/mag.addons.js"></script>
<!-- Jquery -->
jQuery:
<div id="jq_test"></div>
<script>
var jqEl = $('#jq_test');
var children = '';
var jqPush = function (data) {
jqEl.append('<span>' + data + '</span>');
}
var jqClear = function () {
jqEl.empty();
}
</script>
<!-- Angular -->
<div ng-app="app" ng-jq>
Angular:
<span ng-controller="Ctrl" id="angList"><span ng-repeat="item in data track by item">{{::item}}</span></span>
</div>
<!-- Knockout -->
<div id="koapp">
Knockout:
<span data-bind="foreach: data"><span data-bind="text: $data"></span></span>
</div>
<!-- Ember -->
<div id="emapp"></div>
<script type="text/x-handlebars">
Ember:
<span>
{{#each EMapp.data}}<span>{{this}}</span>{{/each}}
</span>
</script>
<!-- React -->
<div id="react">
React: <span id="reactMountNode"></span>
</div>
<!-- Mithril -->
<div id="mithrilapp">
Mithril: <span id="mithrilMountNode"></span>
</div>
<!-- Vuejs -->
<div id="vuejs">
Vuejs: <span id="vuejsMountNode"><span v-repeat="item: data">{{ item }}</span></span>
</div>
<!-- MagJS -->
<div id="magjsapp">
MagJS: <div>
<span id="magjsappMountNode"><span class="magjsdata"></span></span></div>
</div>
<script>
window.getId = function(idx)
{
var d = Date.now() + "";
return idx + "-" + d.substring(d.length - 6);
};
angular.module('app', [])
.controller('Ctrl', ['$scope', Ctrl]);
function Ctrl($scope) {
$scope.data = [];
$scope.push = function(data) {
$scope.data.push(data);
}
};
var KOData = ko.observableArray();
var KOviewmodel = {data: KOData};
var ENV = {EXTEND_PROTOTYPES: false};
var ReactComponent = React.createClass({displayName: 'PerfTest',
getInitialState: function() {
return { data: [] };
},
render: function() {
return (
React.createElement("span", null,
this.state.data.map(function(result) {
console.log(result);
return React.createElement("span", null, result);
})
)
);
}
});
var MithrilData = new Array();
var mithapp = {
controller: function() {
this.data = MithrilData;
},
view: function(ctrl) {
return m("span", [ctrl.data.map(function(datum) { return m('span', datum); })]);
}
}
$(document).ready(function() {
EMapp = Ember.Application.create({
rootElement: '#emapp'
});
EMapp.data = Ember.A();
window.EMclear = function () {
EMapp.data.clear();
};
window.EMpush = function (data) {
EMapp.data.pushObject(data);
};
angular.element(document).ready(function() {
var ang_scope = angular.element(document.getElementById('angList')).scope();
window.ANGclear = function(){
ang_scope.data.length = 0;
ang_scope.$evalAsync();
};
window.ANGpush = function(data){
ang_scope.push(data);
};
});
ko.applyBindings(KOviewmodel, document.getElementById('koapp'));
window.KOclear = function (){
KOData.splice(0, KOData().length);
};
window.KOpush = function (data){
KOData.push(data);
};
var reactComp = React.render( React.createElement(ReactComponent, null), document.getElementById('reactMountNode'));
window.RClear = function() {
reactComp.setState({data: []})
};
window.RPush = function(entry) {
var stateData = reactComp.state.data;
stateData.push(entry);
reactComp.setState({data: stateData});
}
m.mount(document.getElementById("mithrilMountNode"), m.component(mithapp));
window.Mclear = function() {
m.startComputation();
MithrilData.splice(0);
m.endComputation();
};
window.Mpush = function(data) {
MithrilData.push(data);
}
var vueInstance = new Vue({
el: '#vuejsMountNode',
data: {
data: []
}
});
window.VueClear = function(){
vueInstance.data = []
};
window.VuePush = function(data){
vueInstance.data.push(data);
};
var MagJSData = ["TestMagJS"];
var magjsdataNode = {
view: function(state, props) {
state.magjsdata = MagJSData;
}
}
var magjsapp = {
view: function(state, props) {
state.div = mag.module("magjsappMountNode",magjsdataNode);
}
}
mag.module("magjsapp",magjsapp);
window.MagJSclear = function() {
MagJSData.splice(0);
};
window.MagJSpush = function(data) {
MagJSData.push(data);
};
window.MagJSforceRedraw = function(data) {
mag.redraw(true);
}
MagJSclear();
});
</script>
Ready to run.
Test | Ops/sec | |
---|---|---|
Angular |
| ready |
Knockout |
| ready |
React |
| ready |
Mithril |
| ready |
vuejs |
| ready |
Ember |
| ready |
jQuery |
| ready |
MagJS |
| ready |
You can edit these tests or add more tests to this page by appending /edit to the URL.