2012-03-19 4 views
20

Tôi luôn nghĩ rằng, vì JavaScript là một chuỗi, tôi có thể đính kèm các trình xử lý sự kiện mà không lo lắng về các trình xử lý được thực hiện trong khi tôi đang thực thi mã. Trước sự ngạc nhiên của tôi, tôi thấy rằng họ có thể. Theo this answer, hộp thoại 'Không phản hồi tập lệnh' có thể khiến các sự kiện được nâng lên trong khi tập lệnh vẫn đang chạy.luồng JavaScript có thể thực thi bị gián đoạn không?

Tôi thử nghiệm này với đoạn mã sau:

<script> 
    function loop() { 
     var cond; 
     onblur = function (event) { 
      cond = false; 
     }; 
     cond = true; 
     while (cond) 
      ; 
     alert('loop exited!'); 
    } 
</script> 
<button onclick="loop()">loop()</button> 

(jsFiddle)

Trong Firefox 11.0, chức năng in "loop thoát" sau khi nhấp vào tiếp tục. Vòng lặp dường như bị tạm dừng, với các sự kiện được phép thực hiện. Điều này giống như một số Unix signal, tạm thời thay đổi ngữ cảnh của chuỗi đích. Nhưng nó nguy hiểm hơn nhiều, vì nó cho phép thay đổi trạng thái bên ngoài.

Đây có phải là lỗi không? Tôi có nên không còn phụ thuộc vào mô hình JavaScript đơn luồng thực thi và đảm bảo rằng tất cả các tập lệnh của tôi đều được tái nhập không? Hay nó là một lỗ hổng không đáng để theo đuổi mặc dù một trình duyệt chính cho phép điều này xảy ra?

+2

Tôi đoán câu hỏi thực sự sẽ là: "tiêu chuẩn gọi là gì." –

+1

Tôi nghĩ tốt hơn là nên nghĩ đến việc "tạm dừng" xảy ra với một số hành vi tích hợp ('alert()' etc) khi lấy dạng thông dịch bắt buộc "hiệu suất" từ hàm đang chạy vào thời điểm đó, và sau đó , khi "tạm dừng" kết thúc, tiếp tục thực hiện.Nói cách khác, suy nghĩ về chức năng như đã thực sự trở lại trong khi "tạm dừng" đang được tiến hành, và sau đó được tiếp tục như là một sự tiếp tục được tiếp tục. Bằng cách đó, xử lý sự kiện có ý nghĩa hơn rất nhiều, vì nó giống như xử lý sự kiện thông thường. – Pointy

+7

Nhận lời nhắc "không phản hồi" không phải là điều bình thường bạn nên thiết kế. Ứng dụng của bạn bị hỏng là người dùng đã từng nhận được một trong các hộp thoại đó. Bạn nên thiết kế kịch bản của bạn để lời nhắc "không phản hồi kịch bản" không bao giờ xảy ra và sau đó bạn sẽ không phải lo lắng về việc tái nhập. Có vẻ như tôi là một lỗi nhỏ mà một trình duyệt chính cho phép các sự kiện kích hoạt khi được nhắc, nhưng tôi nghĩ việc sửa chữa mã của bạn quan trọng hơn nhiều để lời nhắc không bao giờ xảy ra và điều này không bao giờ là vấn đề. – jfriend00

Trả lời

2

Vì vậy, nếu bạn tạo vòng lặp vô hạn, bạn sẽ treo mã JavaScript của mình. Các trình duyệt khác sẽ xử lý điều này theo cách khác. Firefox 11 cho tôi ném lên một cửa sổ nói rằng kịch bản của bạn đã treo. Chrome hiện đang quay cho tôi.

Điều này sẽ chứng minh vấn đề. Không bao giờ gọi alert() trong FF11 hoặc Chrome 17.

while(true){} 
alert("sucks"); 

http://jsfiddle.net/JCKRt/1/

Bạn hỏi về báo cáo đồng bộ trong JavaScript. Có một vài câu lệnh đồng bộ khác sẽ chặn việc thực thi JavaScript như alert(), confirm(), các cuộc gọi ajax đồng bộ và hơn thế nữa.

Bạn thường muốn tránh mọi thứ đồng bộ trong JavaScript! Nếu bạn muốn mọi thứ tạm dừng, bạn có thể muốn nghĩ lại thiết kế. JavaScript là sự kiện được điều khiển. Bạn không cần nó quay trong một vòng lặp while, vì không có gì trên trang sẽ hoạt động bao gồm mọi sự kiện như nhấp chuột, v.v.

+0

Liên quan: https://bugzilla.mozilla.org/show_bug.cgi?id=340345 Bây giờ có ít nhất một trường hợp đặc biệt trong Mozilla để cắm bộ hẹn giờ trong khi đồng bộ XHR đang được tiến hành, nhưng trường hợp chung ít rõ ràng hơn. – ephemient

+2

Tôi thấy rằng "tự đánh vào mặt" chỉnh sửa ... – Timothy003

+0

Nếu bạn cần quay vòng lặp trong một thời gian - mà không chặn sự kiện giao diện người dùng - bạn có thể sử dụng công nhân web: https: //developer.mozilla.org/En/Using_web_workers # Performing_computations_in_the_background –

0

Tôi nghĩ rằng vấn đề xảy ra khi bạn bắt đầu xử lý sự kiện.

Thay vì sử dụng vòng lặp while, hãy xem xét sử dụng hàm đệ quy.

Dưới đây là một số sửa đổi tôi đã thực hiện cho mã của bạn nên thực thi như mong muốn.

<head> 
    <script> 
    function loop(that) { 
     var cond; 
     that.onblur = function (event) { 
      cond = false; 
     }; 
     cond = true; 
     var loop = 0 
     var xy = function x(){ 
      if(cond == true){ 
       loop++;   
       setTimeout(function(){xy()},0); 
      } else { 
       alert('loop exited! - '+loop); 
       return true; 
      } 
     } 
     xy(); 
    } 
    </script> 
</head> 
<body> 
    <button onclick="this.focus(); loop(this)">loop()</button> 
</body> 

Sử dụng setTimeout() với độ trễ 0 nên cho phép mọi sự kiện nhảy vào mà không gặp bất kỳ sự cố nào. Mã vòng lặp của bạn sẽ không được thực hiện gần như nhanh chóng nhưng bạn sẽ chỉ phải kiểm tra nó và xem.