24 karma · joined January 20, 2014
The way that the Backbone TodoView is designed does not take into account the possibility of a user adding 100 items using the dom within a tight loop. Probably because such a use case is impossible outside of this type of benchmark. By doing so the Backbone implementation ends up performing a lot of unnecessary renders. Therefore as far as Backbone performance is concerned this benchmark is not indicative of any real world scenario.
Just to re-iterate; when you're loading a set of todos from your local storage to display when the user first opens the page, you would not populate the "new todo" input box and fake an enter event for each item that you want to add. Instead you would reset the Backbone.Collection with a list of your new todos (go through the interface). That's basically the change I made to the benchmark. Sorry if it wasn't clear.
They play to the strengths of the virtual dom approach by manipulating the benchmark via dom instead of what ever interface was implemented within each TodoMVC implementation.
So I forked the benchmark and changed both the Backbone and Mercury implementations to work through their respective apis.
Here it is: https://github.com/smelnikov/todomvc-perf-comparison
as you can see the giant gap between Backbone and mercury is now gone while both tests perform the exact same tasks. (feel free to step through it in the debugger to see for yourself)
Here's my commit log: https://github.com/smelnikov/todomvc-perf-comparison/commit/...
Note: I've added a new method to the Backbone implementation for toggling completed state as the old one was horribly in-efficient. This is not something inherit in Backbone but rather is specific to this TodoMVC implementation. See my comments in the commit log.
Note 2: Exoskeleton, which is basically backbone without the jQuery dependency is roughly 2-3x faster than vanilla backbone, I'm going to predict that it will actually be significantly faster than mercury.
Note 3: I think the virtual dom is great and seemingly has many benefits but I feel as though the speed benefit has been greatly exaggerated.
Benchmark 1) This benchmark deals with adding a bunch of todos and seeing how fast they render. The major performance impact here seems to be jQuery. Specifically jQuery event delegation. I was surprised to find that binding DOM events in jQuery are incredibly slow, in fact the majority of the time in that benchmark is spent event binding. For comparison have a look at exoskeleton, a Backbone fork which removes the jQuery dependency and uses the native DOM methods instead. It's also available on todomvc.com and uses pretty much the same code as the Backbone todo implementation.
Given the following benchmark :
var benchmark = function() {
app.todos.reset();
var s = [];var i=0; while (i<1000) {s.push({title:'foo'});i++};
var t = performance.now();
app.todos.reset(s);
return performance.now() - t;
}
Backbone: (http://todomvc.com/architecture-examples/backbone/) >>benchmark()
>>667.2439999965718
Exoskeleton: http://todomvc.com/labs/architecture-examples/exoskeleton/ >>benchmark()
>>226.4119999963441
It's worth mentioning that Backbone has a couple pull requests open that is meant to address this.Benchmark 2) This benchmark deals with toggling all of the todos events at once. It builds up 200 todos and toggles them on and off 5 times.
The problem lies with using 'all' and 'change' events way too liberally within the todo application. Which causes a ton of needless render calls. During the course of this benchmark the main view has render called on it 6000 times (!) while the child views have render called on them for a total of 3000 times. I'm actually surprised that Backbone is as fast as it is given those type of numbers. What should happen is the main view should only need to render a total of 5 times (once for each toggle) and the child views 1000 times (200 items x 5 times).