2012-06-06 21 views
4

我想知道綁定到事件的方法是異步調用還是不在JavaScript中?在我的情況下,我使用Backbone.js來構建一個應用程序。我使用事件聚合器在視圖之間進行通信。方法綁定到異步調用的事件還是不在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

,事件在骨幹引發的相關部分是這樣的:

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之後繼續執行之前,這些當然不能保證完成。這可以通過使用回調來緩解,這些回調可以通過使用延期/承諾來觸發完成或更好。

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 

Check the jsFiddle

+1

如果你查找'trigger'的源代碼:http://documentcloud.github.com/backbone/backbone.js,你可以看到它只是簡單的調用了綁定的回調函數。 – biziclop