Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is Backbone's trigger() synchronous or asynchronous?

I'm building a generic Backbone view for managing multiple child views. I sometimes need to perform logic to prepare these views before they are rendered. I'm considering using Backbone events to enable a pre_render hook, like this:

view = new (this.child_view);
this.trigger('pre_render', view);
view.render();

Will the events called by trigger() be performed synchronously, thus guaranteeing that they will all finish before the render() line is called?

like image 788
Brad Koch Avatar asked Dec 18 '12 00:12

Brad Koch


2 Answers

Basically, yes, it's synchronous.

Here's the relevant section from the source:

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(this, events, args);
  if (allEvents) triggerEvents(this, allEvents, arguments);
  return this;
},

The import function is triggerEvents, which actually calls the handlers. According to the comments, it's just an optimized dispatcher. Notice that they're all calling .call() and .apply(), so the callback will complete before control is handed back to the caller.

var triggerEvents = function(obj, events, args) {
    var ev, i = -1, l = events.length;
    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, args[0]);
    return;
    case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, args[0], args[1]);
    return;
    case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, args[0], args[1], args[2]);
    return;
    default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args);
    }
};

As others have mentioned, though, the trigger handlers are free to schedule their own callbacks if they are so inclined. Thus, whether or not the handlers will have finished their work before returning is dependent on the handler code itself.

like image 147
voithos Avatar answered Oct 02 '22 18:10

voithos


Yes, they are synchronous. However, a function triggered by this event is free to use setTimeout or make ajax requests and if so those will not have completed by the time the trigger call returns and the code proceeds to call render. So yes every bound event handler will have been invoked but not necessarily completed its entire set of processing. Because the trigger API itself does not use callbacks or promises, there is no straightforward way to know when all event handlers are complete. If necessary, you would have to implement such an API yourself and fire a distinct event when everything was done including any asynchronous processing. However, in day to day programming, most of those event handlers are synchronous and if not, the code is usually structured such that proceeding will not cause the application to misbehave. If you need to change this contract, it's a code smell that your application design is not harmoniously using the event system and you may want to think about different approaches to your problem.

like image 35
Peter Lyons Avatar answered Oct 02 '22 17:10

Peter Lyons