Tuesday, April 26, 2011

Backbone.js vs Knockout.js

After having spent quite some time with Backbone I wanted to see what alternatives are available, so I tried Knockout.js out :).

A very good tutorial for Knockout can be found on the official website.
Knockout applies the MVVM pattern in place of the more traditional MVC.
With this design the view does not consume data coming directly from the model but from the view-model, which acts as an adapter to the model.

By writing:
Welcome 
and calling
ko.applyBinding(viewModel);
your view will always be updated as soon as viewModel changes.
And it is not finished here, using a dependent observable you can also automagically update composed info in your View.
While this can save a lot of time (and code) you will end up mixing Javascript with Html.
On the other hand, Backbone does not provide a specific View technique allowing you to choose the one you prefer. More code is needed, since you will need to listen for events from the model and update the page, but this is something made quite easy to do and to maintain with the Backbone.View.events property.

In Knockout you can also use templates, the default is JQuery template but if you want to use another one that is a more advanced task requiring some understanding of Knockout internals.
As I said before, Backbone allows you instead to choose the one you prefer.

And what about performance? Still from the Knockout's documentation:
if a template reads the value of an observable, that template binding becomes dependent on that observable, which causes that template binding to be re-evaluated if the observable changes.
This means that any time a viewmodel changes the whole template will be re-evaluated...with Backbone you can instead just update the part of the view interested by the change:
this.model.bind("change",function(model){
this.$('css selector').html(model.get('changedAttribute'));
})

Another point is that Knockout does applies the MVVM pattern but only partially...the Model is left out and all the methods like parse,validate and others with it.

Last remark: the minified version of Backbone.js is 4kb while Knockout.js's one is 28.

In conclusion, it can be quite easy to figure out which library I prefer but this does not mean Knockout is completely to ignore! Depending on your case it can actually be even better than Backbone, especially if you do not heavily communicate with REST services, you use JQuery template (which is great) and your page is not under heavy load.

UPDATE

After using Backbone for about 2 years I have changed my opinion in regards to automatic binding.
While it is great to have fine grained control over events and UI updates, this is an approach that does not scale very well. As soon as the application becomes more complicated, the code can suffer from it and you can end up with a lot of listeners moving updates back and forth from the UI to the model and from model to model.
Data binding can save you a lot of time and headaches. Mixing logic with view is a price worth paying. The view could still be viewed in a browser as plain HTML, allowing designers and programmers to work in parallel.
This does not mean I prefer Knockout over Backbone but I think that a more advanced and opinionated framework like AngularJs or Ember is necessary for sophisticated web applications.

6 comments:

  1. Your remarks on performance problems with Knockout because it re-evaluates the whole template each time are way off.

    <span data-bind="text: changedAttribute"></span>

    Will operate in exactly the same manner as your backbone code. It will write to the text attribute of the span and do nothing else.

    ReplyDelete
  2. Hi Peter,
    I think we are talking about different things.
    What you show in your example is the normal behavior of Knockout.js for binding observers and in that case, as you say, only the span is updated.
    What I talk about is instead the template binding itself: http://knockoutjs.com/documentation/template-binding.html
    As it says in the documentations:
    "Knockout automatically re-renders templates when any observables (or dependent observables) that they reference change value. In this example, the template will be re-rendered each time you click the button to make the person older."
    You can find an example at http://knockoutjs.com/examples/templating.html
    Here every time a new child is added the whole childrenTemplate is re-rendered.
    This is because the observable is the children array in this case so every time it changes the whole template is re-rendered.
    Diego

    ReplyDelete
  3. Nice post, thanks. Dinatih

    ReplyDelete
  4. Regarding the templates and Knockout:
    If you use special KnockoutJS syntax, KnockoutJS is in control of what is rerendered using the template. For example you can use the following:

    <tbody data-bind="template: {name:'reservationTemplate', foreach: seats}"></tbody>

    <script type="text/x-jquery-tmpl" id="reservationTemplate">
    <tr>
    <td>${name || 'Anonymous'}</td>
    <td>${meal().mealName}</td>
    <td>${meal().price}</td>
    <td>${new Date}</td>
    </tr>
    </script>

    And you will see that only the ones that change are updated.

    ReplyDelete
  5. Thanks for the write up. I just want to mention that Backbone is not Model-View-Controller pattern. The C here stands for Collection. Its a common misconception because they used the common acronym and it is misguiding to developers. Source: http://addyosmani.com/blog/large-scale-jquery/

    ReplyDelete