Search code examples
jquerybackbone.jscoffeescriptbackbone-events

Blocking by functions bound to Backbone triggered events


If I have a function bound to a Backbone object event, will triggering that event from another context block programme flow until the bound functions have executed?

For example, a collection of todos:

class App.Collections.Todos extends Backbone.Collection
  model: App.Models.Todo

  initialize: ->
    @collection.on 'will_change:selected', @logUnselection, this
    @collection.on 'change:selected', @logSelection, this

  logUnselection: (todo) ->
    for t in @collection.models
      console.log "unselected!"

  logSelection: (todo) ->
    console.log "selected!"

And the view for a single todo has this:

class App.Views.Todo extends Backbone.View

  events:
    'click': 'select'

  select: (e) ->
    @model.collection.trigger('will_change:selected', @model)
    @model.set(selected: true)

When clicking a todo will the output always look like this, no matter how long the code in logUnselection takes to execute?

unselected!
unselected!
unselected!
unselected!
...
unselected!
selected!

Or will execution continue while the event triggers the bound function, possibly resulting in this:

unselected!
unselected!
selected!
unselected!
...
unselected!

Solution

  • Trigger will block execution.

    From Backbone's annotated source, this is what is happening when you call trigger. You can see that the triggerEvents function simply executes the registered events for this trigger.

    trigger: function(name) {
      if (!this._events) return this;
      var args = slice.call(arguments, 1);
      if (!eventsApi(this, 'trigger', name, args)) return this;
      var events = this._events[name];
      var allEvents = this._events.all;
      if (events) triggerEvents(events, args);
      if (allEvents) triggerEvents(allEvents, arguments);
      return this;
    },
    
    ... 
    
    var triggerEvents = function(events, args) {
    var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2];
    switch (args.length) {
      case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return;
      case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return;
      case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return;
      case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return;
      default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args); return;
    }
    };