2012-03-23 27 views
6

Tôi có một số quá trình xử lý sẽ mất vài giây để tôi muốn thêm chỉ báo trực quan trong khi đang xử lý.Bản chất đồng bộ/không đồng bộ của hiển thị trình duyệt và thực thi javascript

.processing 
{ 
    background-color: #ff0000; 
} 

<div id="mydiv"> 
    Processing 
</div> 

Script:

$("#mydiv").addClass("processing"); 
// Do some long running processing 
$("#mydiv").removeClass("processing"); 

Tôi ngây thơ nghĩ rằng lớp sẽ được áp dụng cho các div và giao diện người dùng sẽ được cập nhật. Tuy nhiên, chạy điều này trong trình duyệt (trong Firefox ít nhất) div không bao giờ được đánh dấu. Ai đó có thể giải thích cho tôi lý do tại sao div của tôi không bao giờ được đánh dấu? Lớp được thêm vào, quá trình xử lý diễn ra và sau đó lớp được loại bỏ; giao diện người dùng không được cập nhật ở giữa và người dùng không bao giờ nhìn thấy nền màu đỏ.

Tôi biết JS là đơn luồng nhưng tôi luôn cho rằng hiển thị trình duyệt sẽ chạy đồng bộ và khi DOM được cập nhật. Giả định của tôi có đúng không?

Và quan trọng hơn, cách được khuyến nghị để đạt được hiệu ứng này là gì? Tôi có phải dẫn đến việc sử dụng setTimeout để xử lý chậm không đồng bộ và làm việc với một cuộc gọi lại không? Phải có một cách tốt hơn vì tôi thực sự không cần bất kỳ hành vi không đồng bộ nào ở đây; Tôi chỉ muốn giao diện người dùng làm mới.

EDIT:

JSFiddle: http://jsfiddle.net/SE8wD/5/

(Lưu ý, bạn có thể cần phải tinh chỉnh số lần lặp lại vòng lặp để cung cấp cho bạn một sự chậm trễ hợp lý trên máy tính của riêng bạn)

+1

Tôi tin rằng những thay đổi như vậy sẽ trực tiếp thực hiện với DOM, nhưng trình duyệt sẽ đợi cho đến khi quá trình thực thi JavaScript "không hoạt động" trước khi thực hiện bất kỳ thao tác nào. – pimvdb

+0

"Thực hiện một số xử lý đang chạy dài" có một số cuộc gọi không đồng bộ? (ajax, settimeout etc) –

+0

Tôi thực sự không thể thấy mã của bạn gặp vấn đề gì, vì có vẻ như bạn đã đăng tải. Có lẽ có một số '! Quan trọng' trong tập tin css bên ngoài của bạn. Bạn có chắc là class được thêm vào (bạn đã kiểm tra nó qua firebug) và quá trình này có thực sự kéo dài lâu không? có thể nó sẽ xảy ra quá nhanh –

Trả lời

0

Force a redraw. Ngoài ra, hãy sử dụng Soren's code vì quá trình xử lý trên chuỗi giao diện người dùng có vẻ không tốt ...

+0

Tuy nhiên, các plugin jQuery dường như không hoạt động vào lúc này. Đã thêm một giải pháp thay thế. Có thể bạn không cần trì hoãn 'n.parentNode.removeChild (n)'; nếu có, vui lòng chỉnh sửa câu trả lời của tôi. –

+0

Tôi đã thử điều này trên jsFiddle của mình mà không thành công. Tôi rõ ràng là không sử dụng nó đúng cách. Bạn có thể thêm vào Fiddle được không? – njr101

+0

Xin lỗi, nhưng Fiddle không hoạt động. Lớp được áp dụng và sau đó tập lệnh hủy bỏ với một lỗi tập lệnh. Thông báo "Đã hoàn tất" không bao giờ được hiển thị. – njr101

1

Tôi không khuyến nghị đóng băng trình duyệt cho tập lệnh cân nặng. Trong trường hợp này, tôi muốn thay đổi mã để không đóng băng trình duyệt và DOM. Nếu trong mã của bạn có một số vòng lặp, bạn có thể gọi một hàm có độ trễ (sử dụng setInterval) và lưu trữ một số biến trạng thái ở đâu đó. Ví dụ:

for(var i=0; i<1000000; i++) { 
    // do something 
} 

thể là:

var i = 0; 
var intervalID; 
var _f = function() { 
    // do something 
    i++; 
    if(i==1000000) clearInterval(intervalID); 
} 
intervalID = setInterval(_f,1); 

Hoặc một cái gì đó tương tự và nhiều hơn nữa được tối ưu hóa. Mã của bạn sẽ phức tạp hơn một chút và chậm hơn ... nhưng vì vậy bạn ngăn chặn trình duyệt bị đóng băng và bạn có thể tạo thanh trạng thái tải trước nâng cao.

+0

Cảm ơn, đây là ý của tôi khi tôi đề cập đến 'setTimeout'. Tôi nhận ra tôi có thể làm điều này nhưng tôi đã hy vọng tránh được sự phức tạp của các cuộc gọi không đồng bộ. Điều đó mở ra một lớp toàn bộ các vấn đề khác, nơi trạng thái không xác định khi gọi lại async xảy ra. – njr101

+0

Tôi biết. Bạn cũng có thể xem nhân viên web http://www.html5rocks.com/en/tutorials/workers/basics/ –

+0

Cảm ơn bạn đã liên kết. Thú vị, nhưng tiếc là sẽ không giúp tôi khi tôi cần hỗ trợ qua trình duyệt. – njr101

1

Bạn có thể nên xử lý trong một sự kiện riêng biệt, như thế này;

$("#mydiv").addClass("processing"); 
setTimeout(function(){ 
    // This runs as a seperate event after 
    // Do some long running processing 
    $("#mydiv").removeClass("processing"); 
},1); 

Bằng cách đó trình duyệt nên vẽ lại màn hình với processing, trong khi bước dài chạy sẽ bắt đầu như một sự kiện riêng biệt, và loại bỏ các thông điệp xử lý khi thực hiện xong.

+0

Cảm ơn, đây là những gì tôi nghi ngờ. Tôi thực sự hy vọng có một cách để tránh lực này trình duyệt tái xuất hiện sau khi thay đổi DOM. – njr101

+0

cảnh báo - Tôi thấy nó bắt đầu hoạt động sau khi hết thời gian 5ms - mọi thứ ngắn hơn và chrome vẫn chờ. – user2486570

+0

@ user2486570 - Tôi nghi ngờ điều đó - JS là đơn ren vòng lặp sự kiện - vì vậy nó chỉ có những điều kiện chủng tộc bạn tạo cho mình - nếu bạn thấy một vấn đề 5ms là có lẽ là bởi vì bạn có cái gì khác đang chạy với một bộ đếm thời gian hoặc một Sự kiện sẵn sàng DOM xung đột với mã khác của bạn. – Soren

0

Trình duyệt hoàn toàn miễn phí về thời điểm sơn lại và khi nào cần chỉnh lại. Động cơ khác nhau sẽ hiển thị hành vi khác nhau. Để đọc thêm, hãy xem When does reflow happen in a DOM environment?. Trong ví dụ của bạn, trình duyệt sẽ thấy bạn thêm một lớp và xóa lớp đó ngay sau đó, vì vậy, anh ấy có thể không làm bất kỳ điều gì hiển thị.

Để tránh điều đó, bạn có thể áp dụng tính năng buộc vẽ lại hoặc làm cho tính toán của bạn không đồng bộ với WebWorkers hoặc setTimeout hoặc gì đó.

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