2013-08-20 32 views
14

Trong khi cố gắng để trả lời this question, tôi gặp một hành vi kỳ lạ (mà không phải là giống nhau: là mình do quá ít lần lặp lại, tôi có quá nhiều):Một vòng lặp 3,000,000,000 lặp cư xử kì lạ

HTML:

<button id="go">it will be legend...</button> 
<div id="output"></div> 

JS:

var output = document.getElementById('output'); 
document.getElementById('go').onclick = function() { 
    output.textContent += 'wait for it...'; 
    for (var i=0; i<3000000000; i++) { 
     var unused = i; // don't really care 
    } 
    output.textContent += ' dary!'; 
}; 

vòng lặp mất vài giây để thực hiện, vì 3,000,000,000 lần lặp của nó.

Khi nút được nhấn vào, những gì tôi mong đợi:

  1. wait for it... xuất hiện
  2. quá trình đóng băng một chút vì vòng lặp
  3. dary! xuất hiện

Điều gì thực sự đã xảy ra:

  1. quá trình đóng băng một chút vì vòng lặp
  2. wait for it... dary! xuất hiện cùng

Bất cứ ý tưởng tại sao một hành vi như vậy?

Tự kiểm tra: fiddle.

+1

Ứng dụng có hoạt động theo cách này trong tất cả các trình duyệt không? Hoạt động chính xác nếu bạn thiết lập một thời gian chờ nhỏ – Huangism

+0

Tôi thấy fiddle, đó là thực sự kỳ lạ .... và tôi nghĩ 'looping' là một quá trình đơn giản-vani! –

+1

Ngoài ra, trình duyệt tối ưu hóa các thay đổi đối với DOM/CSS để chúng chỉ được thực thi khi cần thiết (để tránh nhiều lần liên tiếp). –

Trả lời

17

Lý do là chức năng, nói chung, đang thực hiện đồng bộ. Vào lúc bạn đặt đầu ra thành wait for it..., nó đi vào vòng lặp chạy dài và hog luồng. Nếu bạn quấn phần còn lại trong một số timeout, văn bản đầu tiên sẽ xuất hiện như bình thường.

var output = document.getElementById('output'); 
document.getElementById('go').onclick = function() { 
    output.textContent += 'wait for it...'; 
    window.setTimeout(function() { 
    for (var i=0; i<3000000000; i++) { 
     var unused = i; // don't really care 
    } 
    output.textContent += ' dary!'; 
    }, 0); 
}; 

Lưu ý rằng nó vẫn đóng băng giao diện người dùng trong khi xử lý.

Edit: Sử dụng 0 như giá trị chậm trễ trong hoạt động của Chrome, nhưng nó không ở mới nhất Firefox và IE 10. Thay đổi giá trị để 10 công trình trong cả hai trường hợp.

+0

Tôi chạy điều này trong fiddle, nó vẫn còn in 'chờ đợi cho nó ... dary! 'Với nhau! – Sid

+0

@Sid Tôi đã thử nghiệm nó trong fiddle và có hành vi thích hợp (sử dụng chrome). [JSFiddle] (http://jsfiddle.net/2MrD8/3/). Chỉnh sửa: Chỉ cần thử nghiệm trong firefox và nó đã hiển thị nó với nhau. nếu bạn thay đổi '0' thành' 10' thì nó hoạt động như mong đợi. Có vẻ như firefox đang thực hiện đồng bộ trong một số trường hợp. –

+0

Bạn có thể muốn chỉnh sửa dòng này 'output.textContent + = 'dary!'; }, 0); 'Tôi đặt nó thành 100 và bây giờ nó hoạt động đúng như mong đợi. kiểm tra này [fiddle] (http://jsfiddle.net/2MrD8/4/) – Sid

10

Javascript khá đơn luồng. Nếu bạn đang chạy mã, trang không phản hồi và sẽ không được cập nhật cho đến khi mã của bạn hoàn tất. (Lưu ý rằng đây là cách triển khai cụ thể, nhưng đây là cách tất cả các trình duyệt làm điều đó ngay hôm nay.)

+0

Có cách nào để * lực lượng * các trang được cập nhật với một tin nhắn như mô tả? – gibberish

+1

Chèn độ trễ, như đã đề cập trong các câu trả lời khác. –

0

Giải thích duy nhất tôi thấy là trình duyệt làm mới chế độ xem sau khi javascript được thực thi? Để làm bằng chứng, điều này hoạt động như mong đợi:

var output = document.getElementById('output'); 
document.getElementById('go').onclick = function() { 
    output.textContent += 'wait for it...'; 
    window.setTimeout(count, 100); 
}; 

function count() { 
    for (var i = 0; i < 3000000000; i++) { 
     var unused = i; // don't really care 
    } 
    output.textContent += ' dary!'; 
} 
2

Dark Falcon và Simon Belanger đã cung cấp giải thích nguyên nhân; bài viết này thảo luận về một giải pháp khác. Tuy nhiên, giải pháp này chắc chắn KHÔNG thích hợp cho một vòng lặp lặp 3 tỷ vì nó quá chậm so với việc so sánh.

Theo this SO post by user Cocco, sử dụng setTimeout ít tối ưu hơn requestAnimationFrame cho mục đích này.Vì vậy, đây là cách sử dụng requestAnimationFrame:

jsFiddle example

$(document).ready(function() { 
    var W = window, 
     D = W.document, 
     i = 0, 
     x = 0, 
     output = D.getElementById('output'); 

    function b() { 
     if (x == 0) { 
      output.textContent = 'wait for it...'; 
      x++; 
     } 
     i++; 
     if (i < 300) { 
      //if (i > 20) output.textContent = i; 
      requestAnimationFrame(b); 
     } else { 
      D.body.style.cursor = 'default'; 
      output.textContent += ' dary!'; 
     } 
    } 

    function start() { 
     console.log(D) 
     D.body.style.cursor = 'wait'; 
     b(); 
    } 
    D.getElementById('go').onclick = start; 
}); //END $(document).ready() 

Lưu ý: Để hiển thị thỏa thuận/đánh giá cao, xin vui lòng upvote Cocco's answer trong bài viết ở trên và không thế này. Cảm ơn bạn.

1

Mã của bạn đang thực thi như bạn mong đợi. Vấn đề là trình duyệt sẽ không hiển thị thay đổi của bạn cho tài liệu, cho đến sau khi javascript được thực hiện. Thời gian ra là khắc phục vấn đề này, bằng cách phá vỡ việc thực thi mã thành hai sự kiện riêng biệt. Các mã sau đây sẽ cho thấy những gì bạn mong đợi đang xảy ra.

var output = document.getElementById('output'); 
document.getElementById('go').onclick = function() { 
    console.log('wait for it...';) 
    for (var i=0; i<3000000000; i++) { 
     var unused = i; // don't really care 
    } 
    console.log(' dary!'); 
}; 

Bạn cũng cần phải cẩn thận khi sử dụng giải pháp hết giờ vì việc thực thi không còn đồng bộ.

output = document.getElementById('output'); 
document.getElementById('go').onclick = function() { 
    output.textContent += 'wait for it...'; 
    window.setTimeout(function() { 
     for (var i = 0; i < 3000000000; i++) { 
     var unused = i; 
     // don't really care 
     } 
    output.textContent += ' dary!'; 
    }, 0); 
    output.textContent += ' epic'; 
}; 

Nếu bạn chạy phiên bản này, bạn sẽ thấy rằng 'sử thi' trước khi 'dary'.

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