Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should all Backbone on/off events be replaced with listenTo/stopListening?

Tags:

backbone.js

As far as I have been able to tell, listenTo and stopListening should replace on and off respectively. Do I understand that correctly? Is there any situation where on/off should be used instead of listenTo/stopListening?

Edit:

As I went to refactor my code, it became obvious that there are some cases for on over listenTo. The documentation is pretty clear that it is for when one object listens to another object:

Tell an object to listen to a particular event on an other object.

Therefore, when a collection or model is listening to an event on itself, we should use on instead of listenTo.

Assuming I have this correct...

The simple rule to follow is this:

Use listenTo when listening for events on another object. Use on when listening to events on self.

like image 365
Bart Avatar asked Mar 26 '13 19:03

Bart


2 Answers

Copying an extract from an interesting blog post that I read recently. Hope it helps.

Avoiding common backbone pitfalls: Creating memory leaks by not unbinding events

A common pattern in Backbone.js is creating views that listen on changes in models or collections. This technique is usually intended to allow the view to automatically re-render itself when the underlying data changes. It also means that for large collections we may end up with many views (at least one for every model in the collection) that we may dynamically create or destroy based on changes to the data.

The problem arises when we remove a view (usually by calling its .remove() method), but forgetting to unbind the methods that listen on model changes. In such a case, even though our code may no longer hold a reference to that view, it is never garbage collected since the model still holds such a reference via the event handler.

Take this view for example:

var SomeModelView = Backbone.View.extend({
   initialize: function() {
     this.model.on('change', this.render, this);
   },
   render: function() {
     // render a template
   }
});

When calling the .remove() method, the "change" event handler (our render function) is still bound. So while the DOM element may be removed, the view object itself is never released from memory.

Solving this is easy (especially since Backbone 0.9.x) - all we need to do is to stop using .on() when binding the event handler. instead, we can use the new .listenTo() method, like this:

initialize: function() {
    this.listenTo(this.model, 'change', this.render);
}

The biggest difference here being the shift in responsibility from the model to the view. This means that whenever we call .remove(), the view will automatically unbind any event bound to it using the .listenTo() method, essentially fixing this common leak.

like image 86
sublime Avatar answered Nov 24 '22 09:11

sublime


For the most part, you understand it correctly. Here is a discussion on the matter from their github repository: https://github.com/documentcloud/backbone/issues/1923#issuecomment-11462852

listenTo and stopListening keep track of state. It will take care of cleanup for you at the cost of a little code overhead. In just about every case I can think of you'd want this behavior for your views, but you wouldn't be at fault for handling on/off calls yourself either; they won't be deprecating on and off any time soon.

like image 27
MichaelSmith Avatar answered Nov 24 '22 09:11

MichaelSmith