Angular VS Knockout VS Ember vs CanJS (v151)

Revision 151 of this benchmark created on


Preparation HTML

<script src="https://code.jquery.com/jquery-1.9.1.min.js">
</script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.min.js">
</script>
<script src="https://knockoutjs.com/downloads/knockout-2.2.1.js">
</script>
<script src="https://rawgithub.com/wycats/handlebars.js/1.0.0-rc.4/dist/handlebars.js">
</script>
<script src="http://builds.emberjs.com.s3.amazonaws.com/ember-latest.js">
</script>
<script src="https://canjs.us/release/1.1.5/can.jquery.js">
</script>
<script src="https://underscorejs.org/underscore.js">
</script>
<script src="https://backbonejs.org/backbone.js">
</script>
<!-- CanJS -->
<div id="canapp">
  <h3>
    Can
  </h3>
</div>
<script type="text/ejs" id="canEJS">
  < % items.each(function(item) { % > < span > < %= item % > < /span>
        <% } ) %>
</script>
<!-- Knockout -->
<div id="koapp">
  <h3>
    KO
  </h3>
  <span data-bind="foreach: items">
    <span data-bind="text: $data">
    </span>
  </span>
</div>
<!-- Ember -->
<div id="emapp">
  <h3>
    Ember
  </h3>
  <script type="text/x-handlebars">
    < span > {
      {#each EMAPP.items
      }
    } < span > {
      {
        this
      }
    } < /span>{{/each
    }
    } < /span>
  </script>
</div>
<!-- Angular -->
<div ng-app="ANGAPP" id="angapp" ng-controller="Ctrl">
  <h3>
    Angular
  </h3>
  <span ng-repeat="item in items">
    {{item}}
  </span>
</div>
<!-- Backbone -->
<div id="backboneapp">
  <h3>
    Backbone
  </h3>
  <span class="backbone-items">
  </span>
</div>
<script>
  // Angular
  angular.module('ANGAPP', []).controller('Ctrl', function($scope) {
    $scope.items = [];
    window.ANG = {
      clear: function() {
        $scope.items.splice(0);
        $scope.$digest();
      },
      push: function(item) {
        $scope.items.push(item);
      }
    };
  });

  // KO
  var ko_items = ko.observableArray([]);
  var ko_viewmodel = {
    items: ko_items
  };

  ko.applyBindings(ko_viewmodel, document.getElementById('koapp'));

  window.KO = {
    clear: function() {
      ko_items.splice(0);
    },
    push: function(data) {
      ko_items.push(data);
    }
  }

  //Ember
  window.EMAPP = Ember.Application.create({
    rootElement: $('#emapp')
  });
  EMAPP.items = Ember.A();

  window.EM = {
    clear: function() {
      EMAPP.items.clear();
    },
    push: function(item) {
      EMAPP.items.pushObject(item);
    }
  }

  //CanJS
  var can_items = new can.Observe.List([]);
  $('#canapp').append(can.view('canEJS', {
    items: can_items
  }));

  window.CAN = {
    clear: function() {
      can_items.splice(0);
    },
    push: function(item) {
      can_items.push(item);
    }
  }
  // Backbone.js
  var backboneView = Backbone.View.extend({
    template: _.template("{{#each items}}{{x}}{{/each}}"),
    initialize: function() {
      this.collection = new Backbone.Collection();
      this.collection.on('add', this.render.bind(this));
      _.bindAll(this);
    },
    render: function() {
      this.$el.html(this.template({
        items: _.pluck(this.collection.models, 'attributes')
      }));
    },
    push: function(i) {
      this.collection.add({
        x: i
      });
    },
    clear: function() {
      this.collection.reset();
    }

  });

  window.BB = new backboneView({
    el: "#backboneapp .backbone-items"
  });

  console.log(window.BB);
</script>

Test runner

Ready to run.

Testing in
TestOps/sec
Can
CAN.clear();
can.Observe.startBatch();
for (var i = 0; i < 50; i++) {
  CAN.push(i);
}
can.Observe.stopBatch()
ready
Knockout
KO.clear();
for (var i = 0; i < 50; i++) {
  KO.push(i);
}
ready
Ember
EM.clear();
for (var i = 0; i < 50; i++) {
  EM.push(i);
}
ready
Angular
ANG.clear();
for (var i = 0; i < 50; i++) {
  ANG.push(i);
}
ANG.$scope.$apply();
ready
Backbone
BB.clear()
for (var i = 0; i < 50; i++) {
  BB.push(i)
}
ready

Revisions

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