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

したがって、質問は、ViewA.saveContact()のthis.model.save()が実行される前に、ViewB.setEmailValues()が常に完了するのでしょうか。

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

ご覧のとおり、イベントハンドラーは1つずつ同期的に呼び出されます。

警告:ハンドラーが非同期呼び出しを行う場合、もちろん、実行スタックが。の後に続く前に、これらが完了することは保証されません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 に答える