Backbone vs. Marionette vs. Epoxy vs. React: A Benchmark
HTML
<script src="http://underscorejs.org/underscore-min.js"></script>
<script src="http://backbonejs.org/backbone-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/backbone.marionette/2.2.1/backbone.marionette.min.js"></script>
<script src="//cdn.jsdelivr.net/backbone.epoxy/1.2/backbone.epoxy.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.12.0/react.js"></script>
<script src="http://tiagorg.com/talk-backbone-tricks-or-treats-html5devconf/js/lib/react.backbone.js"></script>
<script src="http://jridgewell.github.io/js-repaint-perfs/incremental-dom/incremental-dom-min.js"></script>
<p>
This is a fork of <a href="http://jsfiddle.net/jhohlfeld/cS66g/light/" target="_top">Jakob Hohlfeld's Backbone vs. Ember vs. React</a> benchmark to compare <b>Backbone.View</b>, <b>Marionette.ItemView</b>, <b>Backbone.Epoxy.View</b>, <b>React.js</b> and <b>VanillaJS</b>. Note that this is just a simple benchmark: you wouldn't be doing this in an actual app.
</p>
<button onclick="runBackbone()">Animate with Backbone</button>
<button onclick="runMarionette()">Animate with Backbone + Marionette</button>
<button onclick="runEpoxy()">Animate with Backbone + Epoxy</button>
<button onclick="runReact()">Animate with Vanilla React</button>
<button onclick="runBackboneReact()">Animate with Backbone + React</button>
<button onclick="runVanilla()">Animate with Vanilla JavaScript</button>
<button onclick="runIDOM()">Animate with Incremental DOM</button>
<button onclick="runBackboneIDOM()">Animate with Backbone + Incremental DOM</button>
<p id="timing"> </p>
<div id="grid"></div>
<script type="x-template" id="underscore-template">
<div class="box" id="box-<%= number %>" style="top: <%= top %>px; left: <%= left %>px; background: rgb(0,0,<%= color %>);">
<%= content %>
</div>
</script>
<script type="text/x-epoxy" id="epoxy-box">
<div class="box"></div>
</script>
CSS
p {
font: 12px/16px Arial;
margin: 10px 10px 15px;
}
button {
font: bold 14px/14px Arial;
margin-left: 10px;
}
#grid {
margin: 10px;
}
#timing {
clear: both;
padding-top: 10px;
}
.box-view {
width: 20px; height: 20px;
float: left;
position: relative;
margin: 8px;
}
.box {
border-radius: 100px;
width: 20px; height: 10px;
padding: 5px 0;
color: #fff;
font: 10px/10px Arial;
text-align: center;
position: absolute;
}
JavaScript
// Change N to change the number of drawn circles.
var N = 300;
// The Backbone implementation:
(function(){
var Box = Backbone.Model.extend({
defaults: {
top: 0,
left: 0,
color: 0,
content: 0
},
initialize: function() {
this.count = 0;
},
tick: function() {
var count = this.count += 1;
this.set({
top: Math.sin(count / 10) * 10,
left: Math.cos(count / 10) * 10,
color: (count) % 255,
content: count % 100
});
}
});
var BoxView = Backbone.View.extend({
className: 'box-view',
template: _.template($('#underscore-template').html()),
initialize: function() {
this.listenTo(this.model, 'change', this.render);
},
render: function() {
this.$el.html(this.template(this.model.attributes));
return this;
}
});
var boxes;
var backboneInit = function() {
boxes = _.map(_.range(N), function(i) {
var box = new Box({number: i});
var view = new BoxView({model: box});
$('#grid').append(view.render().el);
return box;
});
};
var backboneAnimate = function() {
for (var i = 0, l = boxes.length; i < l; i++) {
boxes[i].tick();
}
};
window.runBackbone = function() {
reset();
backboneInit();
benchmarkLoop(backboneAnimate);
};
})();
// The Marionette implementation:
(function(){
var Box = Backbone.Model.extend({
defaults: {
top: 0,
left: 0,
color: 0,
content: 0
},
initialize: function() {
this.count = 0;
},
tick: function() {
var count = this.count += 1;
this.set({
top: Math.sin(count / 10) * 10,
left: Math.cos(count / 10) * 10,
color: (count) % 255,
content: count % 100
});
}
});
var BoxView = Marionette.ItemView.extend({
className: 'box-view',
template:...