2014-04-10 16 views
8

Po dziwnym zachowaniu naszej aplikacji (przy użyciu strophe XMPP i jquery) odkryliśmy, że pętla zdarzeń jquery jest synchroniczna i nie przechwytuje wyjątku.Dlaczego pętla zdarzeń Jquery jest przerywana na wyjątku

Oznacza to, że jeśli pierwsza procedura obsługi zdarzenia zgłosi wyjątek, druga nie zostanie wywołana.

$(document).ready(function() { 
    $(document).bind('foo', onFoo); 
    $(document).bind('bar', onBar); 

    $(document).trigger('foo'); 
    $(document).trigger('bar'); 
}); 

function onFoo(e) { 
    console.log('listener onFoo'); 
    throw 'fail onFoo'; 
} 

function onBar(e) { 
    console.log('listener onBar'); // not called 
} 

Oczekiwaliśmy dwóch wyjść, ale drugi: "listener onBar" nigdy nie był wyświetlany.

Zobacz kod JQuery, w funkcji "trigger", nie ma wzorca try/catch podczas pętli procedur obsługi.

while ((cur = eventPath[i++]) && !event.isPropagationStopped()) { 
    event.type = i > 1 ? 
     bubbleType : 
     special.bindType || type; 

    // jQuery handler 
    handle = (jQuery._data(cur, "events") || {})[ event.type ] && jQuery._data(cur, "handle"); 
    if (handle) { 
     handle.apply(cur, data); 
    } 
... (line 4998 in JQuery 1.10.2) 

Byliśmy zaskoczeni tą realizacją.

W czystym javascriptu wszystkie procedury obsługi są wywoływane, nawet jeśli jeden z nich się zawiesił: http://jsfiddle.net/bamthomas/kgS7A/2/.

Czy ktoś wie, dlaczego zespół JQuery nie pozwala na wykonanie następnego programu obsługi, nawet jeśli poprzedni się zawiesił? Dlaczego wyjątki nie są chwytane?

Dlaczego nie użyli obsługi zdarzeń javascript?

+0

"Dlaczego jQuery nie przechwytuje wyjątków?" - najprawdopodobniej dlatego, że nikt nie myślał, że to może być problem. Zapraszamy do wysłania prośby o wycofanie do repozytorium github. –

+0

Jeśli Twój przewodnik zdarzeń może rzucić, to Twoim obowiązkiem jest złapać wyjątek. Dlaczego miałbyś oczekiwać (lub nawet chcesz), że "trigger" to robi? – Tomalak

+0

Chociaż odkrycie, że jQuery nie przechwytuje wyjątków, może być użyteczne, nie sądzę, aby to pytanie można było obiektywnie odpowiedzieć ... –

Odpowiedz

2

Dzieje się tak z powodu this loop taken from the .dispatch source:

while ((handleObj = matched.handlers[j++]) && !event.isImmediatePropagationStopped()) { 

    // Triggered event must either 1) have no namespace, or 
    // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). 
    if (!event.namespace_re || event.namespace_re.test(handleObj.namespace)) { 

     event.handleObj = handleObj; 
     event.data = handleObj.data; 

     ret = ((jQuery.event.special[handleObj.origType] || {}).handle || handleObj.handler) 
     .apply(matched.elem, args); 

     if (ret !== undefined) { 
      if ((event.result = ret) === false) { 
       event.preventDefault(); 
       event.stopPropagation(); 
      } 
     } 
} 

Jak widać, nie ma try/catch wokół .apply.

Tak właśnie było w przypadku years i years and years.

Nawet gdyby chcieli, zmiana go spowoduje złamanie zbyt dużej ilości istniejącego kodu. Pamiętaj, że wiele rzeczy w jQuery, które wydają się arbitralne, narodziło się w innym czasie.

Możesz oczywiście "naprawić" to w swoim własnym kodzie (zawijając w try/catch z komunikatem o błędzie), ale zaskoczysz prawie każdego.

+0

"zmiana teraz spowoduje złamanie istniejącego kodu." - czy możesz podać przykład? –

+0

@JanDvorak tak. Jest tam wiele kodu w tym dziale, który został zakodowany przy użyciu słynnego "wrzuć jQuery, dopóki nie zadziała". Z tego co wiemy, ktoś może mieć kod podobny do OP i używa rzucania jako sposobu, aby uniemożliwić działanie innym słuchaczom. –

+0

Ew. To okropny sposób na osiągnięcie tego celu. A jednak - dobrze, dzięki. –

Powiązane problemy