A Circle Benchmark: Backbone vs. Ember vs. React vs. Ractive vs. Vue vs. Basis.js
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.min.js"></script>
<script src="http://backbonejs.org/backbone-min.js"></script>
<script src="http://builds.handlebarsjs.com.s3.amazonaws.com/handlebars-v1.3.0.js"></script>
<script src="https://rawgithub.com/ebryn/0bbe6639da1166bef3ee/raw/c5f715bbee4200d328065fdb34b0bb49f2d748cf/ember-htmlbars-dont-use-me-anywhere-else.prod.js"></script>
<script src="http://react.zpao.com/builds/master/latest/react.min.js"></script>
<script src="https://cdn.rawgit.com/vuejs/vue/50cf2ab528e2c272eb852f96ebb00f220a6371ba/dist/vue.js"></script>
<script src="http://cdn.ractivejs.org/latest/ractive.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/basis.js/1.2.1/basis.min.js"></script>
<script src="https://cdn.rawgit.com/Raynos/mercury/6e260f4cde227683552fd9ca8c3c242be8d5b07c/dist/mercury.js"></script>
<script src="https://code.angularjs.org/tools/system.js"></script>
<script src="https://code.angularjs.org/tools/typescript.js"></script>
<script src="https://code.angularjs.org/2.0.0-alpha.44/angular2.dev.js"></script>
<script>
System.config({
transpiler: 'typescript',
typescriptOptions: {
emitDecoratorMetadata: true
},
map: {
app: "https://cdn.rawgit.com/cheapsteak/ef4fea6105469ea34a4e/raw/66ec2e2c6b6df67a95408805d582e5cfd796da17"
},
packages: {
app: {
main: './test-angular.ts',
defaultExtension: 'ts'
}
}
});
System.import('app')
.catch(console.error.bind(console));
</script>
<p>
This is a fork of <a href="http://jsfiddle.net/jashkenas/CGSd5/" target="_top">jashkenas's Ember/Backbone</a> benchmark to include Vue.js. Note that this is just a simple benchmark: you wouldn't be doing this in an actual app.
</p>
<p>The original fork was clocking the loops synchronously which was not accurate. This fork fixes that, and also gives a 300ms pause before clock starts to offset...
CSS
p {
font: 12px/16px Arial;
margin: 10px 10px 15px;
}
button {
font: bold 14px/14px Arial;
margin-left: 10px;
padding: 3px;
margin-top: .5em;
}
#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.
window.N = 100;
// 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.model.bind('change', this.render, this);
},
render: function() {
this.$el.html(this.template(this.model.attributes));
return this;
}
});
var EfficientBoxView = Backbone.View.extend({
className: 'box-view',
template: _.template($('#underscore-template').html()),
styleTemplate: _.template("top: <%= top %>px; left: <%= left %>px; background: rgb(0,0,<%= color %>);"),
boxEl: undefined,
initialize: function() {
this.model.bind('change', this.update, this);
},
render: function() {
this.$el.html(this.template(this.model.attributes));
this.boxEl = this.el.querySelector('.box');
return this;
},
update: function () {
this.boxEl.setAttribute('style', this.styleTemplate(this.model.attributes));
this.boxEl.innerHTML = this.model.attributes.content;
}
});
var boxes;
var backboneInit = function(useEfficientVersion) {
var boxView = useEfficientVersion ? EfficientBoxView : BoxView;
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...