CanJS EJS Live Binding Performance
JavaScript performance comparison
Preparation code
<script src="http://underscorejs.org/underscore-min.js">
</script>
<script src="http://yui.yahooapis.com/3.5.0pr2/build/yui/yui-min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script src="http://donejs.com/can/dist/edge/can.yui.js">
</script>
<script src="http://backbonejs.org/backbone-min.js">
</script>
<script src="http://cloud.github.com/downloads/SteveSanderson/knockout/knockout-2.0.0.js">
</script>
<style>
p {
font: 12px/16px Arial;
margin: 10px 10px 15px;
}
button {
font: bold 14px/14px Arial;
margin-left: 10px;
}
#grid {
margin: 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;
}
</style>
<script type="text/ejs" id="ejs-template">
<% list(boxes, function( box ) { %>
<div class="box-view">
<div class="box" id="box-<%= box.count %>" style="<%= box.style() %>">
<%= box.content() %>
</div>
</div>
<% }) %>
</script>
<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-handlebars" id="handlebars-template" data-template-name="box">
<div class="box" {{bindAttr id="model.number" style="model.style"}}>
{{ model.content }}
</div>
</script>
<script type="text/x-template" id="knockout-template">
<div data-bind="foreach: boxes">
<div class="box-view">
<div class="box" data-bind="style: {top: top(), left: left(), background: color()}, text: content()"></div>
</div>
</div>
</script>
<script type="text/x-yui-handlebars" id="yui-handlebars-template">
<div class="box" id="box-{{number}}" style="top: {{top}}px; left: {{left}}px; background: rgb(0,0,{{color}});">
{{content}}
</div>
</script>
<div id="can-grid"></div>
<div id="bb-grid"></div>
<div id="ko-grid"></div>
<div id="yui-grid"></div>
<script>
window.N = 100;
YUI().use('can', 'node', function(Y) {
var Box = function() {
return {
count: 0,
top: function() {
return (Math.sin(this.attr('count') / 10) * 10) + 'px';
},
left: function() {
return (Math.cos(this.attr('count') / 10) * 10) + 'px';
},
color: function() {
return 'rgb(0,0,' + (this.attr('count')) % 255 + ')';
},
content: function() {
return this.attr('count') % 100;
},
tick: function() {
this.attr('count', (this.attr('count') + 1));
},
style: function() {
this.attr('count');
return 'top: ' + this.top() + '; left: ' + this.left() + '; background: ' + this.color() + ';';
}
};
};
var boxes;
window.canInit = function() {
boxes = new can.Observe.List();
for (var i = 0; i < N; i++) {
boxes.push(new Box());
}
Y.one('#can-grid').append(can.view('ejs-template', {
boxes: boxes
}));
};
var canAnimate = function() {
for (var i = 0; i < N; i++) {
boxes[i].tick();
}
}
window.runCan = function() {
canAnimate();
};
});
(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 boxes;
window.backboneInit = function() {
boxes = _.map(_.range(N), function(i) {
var box = new Box({
number: i
});
var view = new BoxView({
model: box
});
$('#bb-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() {
backboneAnimate();
};
})();
(function() {
var Box = function() {
this.count = ko.observable(0);
this.top = function() {
return (Math.sin(this.count() / 10) * 10) + 'px';
};
this.left = function() {
return (Math.cos(this.count() / 10) * 10) + 'px';
};
this.color = function() {
return 'rgb(0,0,' + (this.count()) % 255 + ')';
};
this.content = function() {
return this.count() % 100;
};
this.tick = function() {
this.count(this.count() + 1);
}
}
var ViewModel = function(num) {
this.num = num;
this.boxes = ko.observableArray();
for (var i = 0; i < num; i++) {
this.boxes.push(new Box())
}
}
var knockoutAnimate = function() {
for (var i = 0, l = vm.boxes().length; i < l; i++) {
vm.boxes()[i].tick();
}
}
window.knockoutInit = function(){
$('#ko-grid').html($('#knockout-template').html());
vm = new ViewModel(N)
ko.applyBindings(vm, $('#ko-grid')[0]);
};
window.runKnockout = function() {
knockoutAnimate();
};
})();
YUI().use('model', 'view', 'handlebars', function (Y) {
Y.Box = Y.Base.create('box', Y.Model, [], {
initializer: function () {
this.count = 0;
},
tick: function () {
var count = this.count += 1;
this.setAttrs({
top : Math.sin(count / 10) * 10,
left : Math.cos(count / 10) * 10,
color : (count) % 255,
content: count % 100
});
}
}, {
ATTRS: {
top : {value: 0},
left : {value: 0},
color : {value: 0},
content: {value: 0},
number : {}
}
});
Y.BoxView = Y.Base.create('boxView', Y.View, [], {
template: Y.Handlebars.compile(Y.one('#yui-handlebars-template').getContent()),
initializer: function () {
this.get('model').after('change', this.render, this);
},
create: function () {
return Y.Node.create('<div class="box-view" />');
},
render: function () {
var content = this.template(this.get('model').toJSON());
this.get('container').setContent(content);
return this;
}
});
var boxes;
var yuiAnimate = function() {
for (var i = 0, l = boxes.length; i < l; i++) {
boxes[i].tick();
}
};
window.yuiInit = function () {
boxes = _.map(_.range(N), function (i) {
var box = new Y.Box({number: i});
var view = new Y.BoxView({model: box});
Y.one('#yui-grid').append(view.render().get('container'));
return box;
});
};
window.runYUI = function() {
yuiAnimate();
};
});
</script>
<script>
Benchmark.prototype.setup = function() {
window.canInit();
window.backboneInit();
window.knockoutInit();
window.yuiInit();
};
Benchmark.prototype.teardown = function() {
$('#can-grid').empty();
$('#bb-grid').empty();
$('#ko-grid').empty();
$('#yui-grid').empty();
};
</script>
Preparation code output
Test runner
Warning! For accurate results, please disable Firebug before running the tests. (Why?)
Java applet disabled.
| Test | Ops/sec | |
|---|---|---|
CanJS |
|
pending… |
Backbone |
|
pending… |
Knockout |
|
pending… |
YUI |
|
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. Here’s a list of current revisions for this page:
- Revision 1: published by Curtis Cummings
- Revision 2: published by Curtis Cummings
- Revision 5: published by Curtis Cummings
- Revision 6: published
- Revision 7: published by Curtis Cummings
- Revision 8: published
- Revision 9: published by Curtis Cummings
- Revision 11: published
- Revision 12: published
- Revision 15: published
- Revision 16: published
- Revision 20: published by Stan
- Revision 21: published
- Revision 22: published
- Revision 27: published
- Revision 28: published
- Revision 29: published
0 comments