2015-11-26 13 views
14

tôi đã viết mã này được cho là để nói "hi" khi tôi bấm vào nút "hello":Javascript không in văn bản ngay lập tức

<!DOCTYPE html> 

<html> 

<head> 
<script> 
var someLargeNumber = 5000000000; 
function hello() { 
    document.getElementById('hi').innerHTML = "hi"; 
    for(var i = 0; i < someLargeNumber; i++) {} 
} 
</script> 
</head> 

<body> 
<p id="hi"></p> 
<input type="button" value="hello" onclick="hello();"> 
</body> 

</html> 

Nó nói hi, nhưng chỉ sau khi vòng lặp for xong . Tại sao điều này xảy ra và làm cách nào để khắc phục sự cố này?

Cảm ơn

+3

Có lẽ bạn có thể đưa ra các vòng lặp. Tại sao nó lại ở đó? Trình duyệt sẽ không (nhất thiết) lại hiển thị trang cho đến khi trình xử lý "click" được hoàn tất. – Pointy

Trả lời

23

Tại sao điều này xảy ra ...

Vì các trình duyệt chạy JavaScript trên thread UI chính mà họ sử dụng để cập nhật trang, cho một loạt các lý do. Vì vậy, mặc dù bạn đã hiển thị văn bản "hi", nó không được hiển thị cho đến khi mã JavaScript chạy để phản hồi cho sự kiện hoàn tất.

... và cách khắc phục điều này?

Quay lại trình duyệt sau khi thêm văn bản, trước khi thực hiện bất cứ điều gì bạn đang mô phỏng với vòng lặp đó. setTimeout với một sự chậm trễ của 0 phù hợp cho nhiều trường hợp:

var someLargeNumber = 5000000000; 
function hello() { 
    document.getElementById('hi').innerHTML = "hi"; 
    setTimeout(function() { 
     for(var i = 0; i < someLargeNumber; i++) {} 
    }, 0); 
} 

Động cơ JavaScript làm việc cơ bản trong một vòng lặp với một hàng đợi công việc (spec gọi họ là "công việc"). Nó chọn một công việc từ hàng đợi, chạy nó để hoàn thành, và sau đó tìm kiếm công việc tiếp theo. Các trình duyệt (thường) cập nhật giao diện người dùng khi động cơ nằm giữa các công việc. Khi một sự kiện xảy ra, một công việc được xếp hàng đợi để gọi trình xử lý sự kiện. Ở trên chỉ di chuyển vòng lặp vào một công việc mới mà nó xếp hàng qua setTimeout, do đó trình duyệt có cơ hội sau công việc sự kiện và trước khi công việc setTimeout cập nhật giao diện người dùng.

+0

[Câu hỏi/câu trả lời liên quan] (http://stackoverflow.com/questions/779379/why-is-settimeoutfn-0-sometimes-useful) dành riêng cho mẫu 'setTimeout (fn, 0);' –

0

Như trình duyệt đã được trả lời có một chuỗi giao diện người dùng duy nhất.

Một tùy chọn khác là sử dụng Web Worker (miễn là bạn không thực hiện bất kỳ thao tác DOM nào trong chuỗi công nhân), cho phép chạy các thao tác trong một chuỗi khác.

Thêm một file js (nói worker.js)

var someLargeNumber = 5000000000; 
onmessage = function(e) { 
    console.log('Message received from main script'); 
    for(var i = 0; i < someLargeNumber; i++) {} 
    console.log('Posting message back to main script'); 
    postMessage('done'); 
} 

Quay trở lại bạn tập tin chính

<head> 
<script> 
var myWorker = new Worker("worker.js"); 
function hello() { 
    document.getElementById('hi').innerHTML = "hi"; 
    myWorker.postMessage('test'); 
    console.log('Message posted to worker'); 
} 
myWorker.onmessage = function(e) { 
    result.textContent = e.data; 
    console.log('Worker thread is complete'); 
} 
</script> 
Các vấn đề liên quan