Angular VS Knockout VS Ember VS React VS Mithril (v611)

Revision 611 of this benchmark created by Eike Thies on


Description

This is a simple rendering speed test between the most popular libraries/frameworks. I added in Mithril because it's a newcomer with some promise.

Updates:

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!

Preparation HTML

<!-- Jquery -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.0-rc.1/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.1.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.0-beta.1/ember-template-compiler.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ember.js/1.13.0-beta.1/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.11.10/vue.min.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">
  Angular:
  <span ng-controller="Ctrl" id="angList"><span ng-repeat="item in data track by $index">{{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>

<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 = [];
};

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 = $('#angList').scope();

    window.ANGclear = function(){
      ang_scope.data = [];
      ang_scope.$apply();
    };
    window.ANGpush = function(data){
      ang_scope.data.push(data);
      ang_scope.$apply();
    };
  });

  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.module(document.getElementById("mithrilMountNode"), mithapp);
  window.Mclear = function() {
    m.startComputation();
    MithrilData.splice(0);
    m.endComputation();
  };

  window.Mpush = function(data) {
    m.startComputation();
    MithrilData.push(data);
    m.endComputation();
  }
  

  var vueInstance = new Vue({
          el: '#vuejsMountNode',
          data: {
                  data: []
          }
  });
  
  window.VueClear = function(){
          vueInstance.data = []
  };

  window.VuePush = function(data){
                vueInstance.data.push(data);
  };
  

  
});
</script>

Test runner

Ready to run.

Testing in
TestOps/sec
Angular
ANGclear();
for (var i = 0; i < 100; i++)
  ANGpush("nitem"+ getId(i));
ready
Knockout
KOclear();
for (var i = 0; i < 100; i++)
  KOpush("kitem"+ getId(i));
ready
React
RClear();
for (var i = 0; i < 100; i++)
  RPush("ritem"+ getId(i));
ready
Mithril
Mclear();
for (var i = 0; i < 100; i++)
  Mpush("mitem"+ getId(i));
ready
vuejs
VueClear();
for (var i = 0; i < 100; i++)
  VuePush("vitem"+ getId(i));
ready
Ember
EMclear();
for (var i = 0; i < 100; i++)
  EMpush("eitem"+ getId(i));
ready
jQuery
jqClear();
for (var i = 0; i < 100; i++) {
  jqPush('jq-item'+ getId(i));
}
 
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.