简体   繁体   English

方法是否绑定到Javascript / Backbone.js中异步或非异步调用的事件?

[英]Are methods bound to events called asynchronouly or not in Javascript / Backbone.js?

I am wondering if methods bound to events are called asynchronously or not in javascript? 我想知道绑定到事件的方法是否在javascript中异步调用? In my case I am using Backbone.js to build an app. 在我的情况下,我使用Backbone.js来构建一个应用程序。 I use an event aggregator to communicate between views. 我使用事件聚合器在视图之间进行通信。

If I have a method which triggers an event, will the methods in other views bound to that event complete before the rest of the method calling the trigger event is run? 如果我有一个触发事件的方法,那么在调用触发器事件的其余方法运行之前,其他视图中的方法是否会绑定到该事件?

Event aggregator is as follows: 事件聚合器如下:

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

Function call which triggers the event (this function is called from ViewA): 触发事件的函数调用(此函数从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 is bound to the event 'submitContactEditForm' (see relevant code from ViewB below): 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);
},

So the question would be, will ViewB.setEmailValues() always be completed before this.model.save() in ViewA.saveContact() is executed? 那么问题是,ViewB.setEmailValues()总是在ViewA.saveContact()中执行this.model.save()之前完成吗?

The relevant part where events are triggered in backbone is this: 在骨干中触发事件的相关部分是:

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;
}

As you can see, event handlers are called synchronously one by one. 如您所见,事件处理程序是逐个同步调用的。

Warning: If your handlers make asynchronous calls, then of course these will not be guaranteed to complete before the execution stack continues after trigger . 警告:如果您的处理程序进行异步调用,那么当然在执行堆栈在trigger后继续执行之前,这些将无法保证完成。 This, can be alleviated by the use of callbacks that would trigger completion or better by use of Deferred/Promises. 这可以通过使用将通过使用延迟/承诺触发完成或更好的回调来缓解。

It is a very interesting question with a very interesting answer. 这是一个非常有趣的问题,有一个非常有趣的答案。

I was expecting this behavior to be asynchronous but it turned out to be synchronous . 我期待这种行为是异步的,但事实证明它是同步的

I've based my conclusion in this code: 我在这段代码中得出了我的结论:

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();​

That results in this output: 这导致了这个输出:

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 

Check the jsFiddle . 检查jsFiddle

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM