2014-04-10 31 views
8

Sau một hành vi kỳ lạ của ứng dụng của chúng tôi (sử dụng Strophe XMPP và jquery), chúng tôi đã phát hiện ra rằng vòng lặp sự kiện jquery là đồng bộ và không bắt ngoại lệ.Tại sao vòng lặp sự kiện Jquery bị gián đoạn trên ngoại lệ

Điều đó có nghĩa là nếu trình xử lý sự kiện đầu tiên tăng ngoại lệ, điều thứ hai sẽ không bao giờ được gọi.

$(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 
} 

Chúng tôi dự kiến ​​sẽ thấy hai kết quả đầu ra, nhưng thứ hai: "listener onBar" không bao giờ được hiển thị.

Xem mã JQuery, trong chức năng "kích hoạt", không có mẫu thử/bắt trong vòng lặp của trình xử lý.

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) 

Chúng tôi đã rất ngạc nhiên bởi việc triển khai này.

Trong javascript thuần túy, tất cả trình xử lý được gọi ngay cả khi một trong số chúng bị lỗi: http://jsfiddle.net/bamthomas/kgS7A/2/.

Có ai biết tại sao nhóm JQuery không cho phép thực hiện trình xử lý tiếp theo ngay cả khi trình xử lý tiếp theo bị lỗi? Tại sao ngoại lệ không bị bắt?

Tại sao họ không sử dụng trình xử lý sự kiện javascript?

+0

"Tại sao jQuery không nắm bắt ngoại lệ?" - rất có thể là vì không ai nghĩ rằng đây có thể là một vấn đề. Bạn có thể gửi yêu cầu kéo đến repo github của họ. –

+0

Nếu trình xử lý sự kiện của bạn có thể ném, thì bạn có trách nhiệm bắt ngoại lệ. Tại sao bạn mong đợi (hoặc thậm chí muốn) rằng 'trigger' làm điều đó? – Tomalak

+0

Giống như khám phá mà jQuery không nắm bắt ngoại lệ có thể hữu ích, tôi không nghĩ câu hỏi này có thể được trả lời một cách khách quan ... –

Trả lời

2

Điều này xảy ra vì 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(); 
      } 
     } 
} 

Như bạn thấy, không có try/catch xung quanh .apply.

Đó là cách nó đã được cho yearsyears and years.

Ngay cả khi họ muốn, việc thay đổi ngay bây giờ sẽ phá vỡ quá nhiều mã hiện có. Hãy nhớ rằng, rất nhiều thứ trong jQuery mà dường như tùy ý bây giờ được sinh ra trong một thời điểm khác.

Bạn có thể khóa học 'sửa' điều này trong mã của riêng bạn (gói nó trong một thử/bắt với thông báo lỗi), nhưng bạn sẽ ngạc nhiên khá nhiều người khác.

+0

"thay đổi ngay bây giờ sẽ phá vỡ quá nhiều mã hiện có". - bạn có thể cung cấp một ví dụ? –

+0

@JanDvorak có. Có rất nhiều mã trong tự nhiên ở đó đã được mã hóa bằng cách sử dụng jQuery 'nổi tiếng ném vào nó cho đến khi nó hoạt động'. Đối với những gì chúng ta biết, ai đó có thể có mã tương tự như OP và họ đang sử dụng ném như một cách để ngăn chặn người nghe khác chạy. –

+0

Ew. Đó là một cách khủng khiếp để đạt được mục tiêu đó. Tuy nhiên - tốt, cảm ơn. –

Các vấn đề liên quan