After a weird behaviour of our application (using strophe XMPP and jquery), we have discovered that the jquery event loop is synchronous and does not catch exception.
It means that if the first event handler raises an exception, the second one is never called.
$(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
}
We expected to see two outputs, but the second one : "listener onBar" was never displayed.
See JQuery code, in "trigger" function, there is no try/catch pattern during the loop of the handlers.
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)
We have been surprised by this implementation.
In pure javascript, all the handlers are called even if one of them crashed: http://jsfiddle.net/bamthomas/kgS7A/2/.
Does someone know why JQuery team does not allow the execution of the next handler even if the previous one crashed ? Why exceptions are not catched ?
Why didn't they use javascript event handler ?
This happens because of 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();
}
}
}
As you can see, there is no try/catch around .apply
.
That's the way it has been for years and years and years.
Even if they wanted, changing it now will break too much existing code. Remember, lots of things in jQuery that seem arbitrary now were born in another time.
You can of course 'fix' this in your own code (wrapping it in a try/catch with error message), but you'll surprise pretty much everyone else.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With