4

我想知道绑定到事件的方法是否在javascript中被异步调用?在我的例子中,我使用 Backbone.js 来构建一个应用程序。我使用事件聚合器在视图之间进行通信。

如果我有一个触发事件的方法,绑定到该事件的其他视图中的方法是否会在调用触发事件的其余方法运行之前完成?

事件聚合器如下:

var eventAggrigator = _.extend({}, Backbone.Events);
eventAggrigator.on('submitContactEditForm', function() {
  console.log('Contact edit form submit event triggered');
});

触发事件的函数调用(从 ViewA 调用此函数):

saveContact: function(event) {
  var self = this;
  // Prevent submit event trigger from firing.
  event.preventDefault();
  // Trigger form submit event.
  eventAggrigator.trigger('submitContactEditForm');
  // Update model with form values.
  this.updateContact();
  // Save contact to database.
  this.model.save({
    success: function(model, response) {
      console.log('Contact ' + self.model.get('surname') + ' saved');
    },
    error: function(model, response) {
      throw error = new Error('Error occured while saving contact.');
    }
  });
},

ViewB 绑定到事件“submitContactEditForm”(参见下面 ViewB 的相关代码):

initialize: function() {
  _.bindAll(this, 'addSortableFields', 'appendNewField', 'getFieldsHtml', 'removeField', 'render', 'setEmailValues');
  // Bind to event aggregator.
  eventAggrigator.bind('submitContactEditForm', this.setEmailValues);
  this.model = this.options.model;
},
setEmailValues: function() {
  // Extract email form values.
  var emails = _.clone(this.model.get('email'));
  var emailFields = this.$('.email-field');
  _.each(emails, function(email, index) {
    email.value = emailFields.eq(index).val();
  });
  this.model.set('email', emails);
},

所以问题是, ViewB.setEmailValues() 是否总是在 ViewA.saveContact() 中的 this.model.save() 执行之前完成?

4

2 回答 2

4

在主干中触发事件的相关部分是:

trigger: function(events) {
  var event, node, calls, tail, args, all, rest;
  if (!(calls = this._callbacks)) return this;
  all = calls.all;
  events = events.split(eventSplitter);
  rest = slice.call(arguments, 1);

  // For each event, walk through the linked list of callbacks twice,
  // first to trigger the event, then to trigger any `"all"` callbacks.
  while (event = events.shift()) {
    if (node = calls[event]) {
      tail = node.tail;
      while ((node = node.next) !== tail) {
        node.callback.apply(node.context || this, rest);
      }
    }
    if (node = all) {
      tail = node.tail;
      args = [event].concat(rest);
      while ((node = node.next) !== tail) {
        node.callback.apply(node.context || this, args);
      }
    }
  }

  return this;
}

如您所见,事件处理程序被一一同步调用。

警告:如果您的处理程序进行异步调用,那么这些当然不能保证在执行堆栈之后继续执行之前完成trigger。这可以通过使用触发完成的回调来缓解,或者通过使用 Deferred/Promises 更好。

于 2012-06-06T16:34:05.860 回答
0

这是一个非常有趣的问题,有一个非常有趣的答案。

我原以为这种行为是异步的,但结果却是同步的。

我在这段代码中得出了我的结论:

var MyModel = Backbone.Model.extend();

var oneModel = new MyModel();
oneModel.on( "event", eventHandler1 );
oneModel.on( "event", eventHandler2 );

function eventHandler1(){
  for( var i = 0; i < 10; i++ ){
    console.log( "eventHandler1", i );
  }
}

function eventHandler2(){
  for( var i = 0; i < 10; i++ ){
    console.log( "eventHandler2", i );
  }
}

function testEvent(){
  console.log( "testEvent::INI" );
  oneModel.trigger( "event" );
  console.log( "testEvent::END" );
}

testEvent();​

这导致了这个输出:

testEvent::INI
eventHandler1 0
eventHandler1 1
eventHandler1 2
eventHandler1 3
eventHandler1 4
eventHandler1 5
eventHandler1 6
eventHandler1 7
eventHandler1 8
eventHandler1 9
eventHandler2 0
eventHandler2 1
eventHandler2 2
eventHandler2 3
eventHandler2 4
eventHandler2 5
eventHandler2 6
eventHandler2 7
eventHandler2 8
eventHandler2 9
testEvent::END 

检查 jsFiddle

于 2012-06-06T09:16:02.397 回答