Angular VS Knockout VS Ember VS React VS Mithril VS Mercury VS Ractive

JavaScript performance comparison

Revision 424 of this test case created by MadDocNC Ractive with .set .get

Preparation code

<!-- Mercury -->
<script src="https://rawgit.com/Raynos/mercury/master/dist/mercury.js"></script>
<!-- Jquery -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-rc.4/angular.min.js"></script>
<script src="https://cdn.jsdelivr.net/knockout/3.2.0/knockout.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.6.1/ember.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.11.2/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mithril/0.1.21/mithril.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/0.10.5/vue.min.js"></script>
<script src='//cdn.ractivejs.org/latest/ractive.js'></script>

<!-- Angular -->
<div ng-app>
  Angular:
  <span ng-controller="Ctrl" id="angList"><span ng-repeat="item in data">{{item}}</span></span>
</div>


<!-- Knockout -->
<div id="koapp">
  Knockout:
  <span data-bind="foreach: data"><span data-bind="text: $data"></span></span>
</div>

<div id="koappRL">
  Knockout:
  <span data-bind="foreach: data"><span data-bind="text: $data"></span></span>
</div>

<!-- Ember -->

<div id="emapp">
  <script type="text/x-handlebars">
    Ember:
    <span>
      {{#each EMapp.data}}<span>{{this}}</span>{{/each}}
    </span>
  </script>
</div>

<!-- 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>

<!-- Mercuryjs -->
<div id="mercuryjs">
	Mercuryjs: <span id="mercuryjsMountNode"></span>
</div>

<!-- Ractive -->
<div id="ractive">
  Ractive: <span id="ractiveMountNode"></span>
</div>

<script>
  var Ctrl = function($scope){ $scope.data = []; };

  var KOData = ko.observableArray();
  var KOviewmodel = {data: KOData};

  var ENV = {EXTEND_PROTOTYPES: false};

  var ReactData = [];
  var ReactUpdate = null; 
  var ReactComponent = React.createClass({displayName: 'PerfTest',
    getInitialState: function() {
      return { data: ReactData };
    },
    componentDidMount: function() {
      ReactUpdate = this._onData;
    },
    render: function() {
      return (
        React.DOM.span(null, 
          this.state.data.map(function(result) {
            return React.DOM.span(null, result);
          })
          )
        );
    },
    _onData: function() {
      this.setState({ data: ReactData });
    }
  });

  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); })]);
    }
  }

  var h = mercury.h
  var mdata = mercury.array([])
  function mrender(data) {
    return h("span", data.map(function(datum) { return h('span', datum)}));
  }

  mercury.app(document.getElementById('mercuryjsMountNode'), mdata, mrender)
  window.mercuryClear=function(){
    mdata.splice(0,mdata.getLength())
  }

  window.mercuryPush=function(data){
    mdata.push(data)
  }
  


  
  var RactiveComponent = new Ractive({
    el: 'ractiveMountNode',
    template: '{{#data}}{{.}}{{/data}}',
    data: { data: [] }
  });

  window.RactiveClear = function() {
    RactiveComponent.set('data',[]);
  };
  window.RactivePush = function(data) {
    RactiveComponent.push('data',data);
  };



  $(document).ready(function() {
    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 KODataRL = ko.observableArray();
    KODataRL.extend({ rateLimit: 0 });
    var KOviewmodelRL = {data: KODataRL};

    ko.applyBindings(KOviewmodelRL, document.getElementById('koappRL'));
    window.KOclearRL = function (){
      KODataRL.splice(0, KOData().length);
    };
    window.KOpushRL = function (data){
      KODataRL.push(data);
    };



    EMapp = Ember.Application.create({
      rootElement: '#emapp'
    });
    EMapp.data = Ember.A();

    window.EMclear = function () {
      EMapp.data.clear();
    };
    window.EMpush = function (data) {
      EMapp.data.pushObject(data);
    };


    var reactComp = ReactComponent();
    React.renderComponent(reactComp, document.getElementById('reactMountNode'));

    window.RClear = function() {
      ReactData.splice(0, ReactData.length);
      ReactUpdate();
    };

    window.RPush = function(data) {
      ReactData.push(data);
      ReactUpdate();
    }

    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>
    

Preparation code output

<!-- Mercury --> <!-- Jquery --> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-rc.4/angular.min.js"></script> <script src="https://cdn.jsdelivr.net/knockout/3.2.0/knockout.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.6.1/ember.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.11.2/react.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/mithril/0.1.21/mithril.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/0.10.5/vue.min.js"></script> <script src='//cdn.ractivejs.org/latest/ractive.js'></script> <!-- Angular --> <div ng-app> Angular: <span ng-controller="Ctrl" id="angList"><span ng-repeat="item in data">{{item}}</span></span> </div> <!-- Knockout --> <div id="koapp"> Knockout: <span data-bind="foreach: data"><span data-bind="text: $data"></span></span> </div> <div id="koappRL"> Knockout: <span data-bind="foreach: data"><span data-bind="text: $data"></span></span> </div> <!-- Ember --> <div id="emapp"> <script type="text/x-handlebars"> Ember: <span> {{#each EMapp.data}}<span>{{this}}</span>{{/each}} </span> </script> </div> <!-- 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> <!-- Mercuryjs --> <div id="mercuryjs"> Mercuryjs: <span id="mercuryjsMountNode"></span> </div> <!-- Ractive --> <div id="ractive"> Ractive: <span id="ractiveMountNode"></span> </div> <script> var Ctrl = function($scope){ $scope.data = []; }; var KOData = ko.observableArray(); var KOviewmodel = {data: KOData}; var ENV = {EXTEND_PROTOTYPES: false}; var ReactData = []; var ReactUpdate = null; var ReactComponent = React.createClass({displayName: 'PerfTest', getInitialState: function() { return { data: ReactData }; }, componentDidMount: function() { ReactUpdate = this._onData; }, render: function() { return ( React.DOM.span(null, this.state.data.map(function(result) { return React.DOM.span(null, result); }) ) ); }, _onData: function() { this.setState({ data: ReactData }); } }); 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); })]); } } var h = mercury.h var mdata = mercury.array([]) function mrender(data) { return h("span", data.map(function(datum) { return h('span', datum)})); } mercury.app(document.getElementById('mercuryjsMountNode'), mdata, mrender) window.mercuryClear=function(){ mdata.splice(0,mdata.getLength()) } window.mercuryPush=function(data){ mdata.push(data) } var RactiveComponent = new Ractive({ el: 'ractiveMountNode', template: '{{#data}}{{.}}{{/data}}', data: { data: [] } }); window.RactiveClear = function() { RactiveComponent.set('data',[]); }; window.RactivePush = function(data) { RactiveComponent.push('data',data); }; $(document).ready(function() { 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 KODataRL = ko.observableArray(); KODataRL.extend({ rateLimit: 0 }); var KOviewmodelRL = {data: KODataRL}; ko.applyBindings(KOviewmodelRL, document.getElementById('koappRL')); window.KOclearRL = function (){ KODataRL.splice(0, KOData().length); }; window.KOpushRL = function (data){ KODataRL.push(data); }; EMapp = Ember.Application.create({ rootElement: '#emapp' }); EMapp.data = Ember.A(); window.EMclear = function () { EMapp.data.clear(); }; window.EMpush = function (data) { EMapp.data.pushObject(data); }; var reactComp = ReactComponent(); React.renderComponent(reactComp, document.getElementById('reactMountNode')); window.RClear = function() { ReactData.splice(0, ReactData.length); ReactUpdate(); }; window.RPush = function(data) { ReactData.push(data); ReactUpdate(); } 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

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

Testing in CCBot 2.0.0 / Other 0.0.0
Test Ops/sec
Angular
ANGclear();
for (var i = 0; i < 100; i++)
  ANGpush("nitem");
pending…
Knockout
KOclear();
for (var i = 0; i < 100; i++)
  KOpush("kitem");
pending…
React
RClear();
for (var i = 0; i < 100; i++)
  RPush("ritem");
pending…
Mithril
Mclear();
for (var i = 0; i < 100; i++)
  Mpush("mitem");
pending…
vuejs
VueClear();
for (var i = 0; i < 100; i++)
  VuePush("vitem");
pending…
Ember
EMclear();
for (var i = 0; i < 100; i++)
  EMpush("eitem");
pending…
Mercury
mercuryClear();
for (var i = 0; i < 100; i++)
  mercuryPush("mitem");
pending…
Ractive
RactiveClear();
for (var i = 0; i < 100; i++)
	RactivePush("aitem"); 
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.

0 Comments

Angular: {{item}}
Knockout:
Knockout:
React:
Mithril:
Vuejs: {{ item }}
Mercuryjs:
Ractive: