2012-03-23 85 views
6

我有一些處理過程需要幾秒鐘的時間,所以我想在處理過程中添加一個可視化指示器。瀏覽器渲染和javascript執行的同步/異步性質

.processing 
{ 
    background-color: #ff0000; 
} 

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

腳本:

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

我天真地以爲類將應用於div和用戶界面將被更新。但是,在瀏覽器中運行(至少在Firefox中),div永遠不會突出顯示。有人可以向我解釋爲什麼我的div不會突出顯示嗎?該類被添加,處理髮生,然後該類被刪除;用戶界面不會在兩者之間更新,用戶也不會看到紅色背景。

我知道JS是單線程的,但我總是推測瀏覽器呈現將在DOM更新時同步運行。我的假設是否不正確?

更重要的是,達到這種效果的推薦方法是什麼?我是否必須使用setTimeout來使緩慢處理異步並使用回調工作?必須有更好的方法,因爲我在這裏確實不需要異步行爲;我只想要刷新UI。

編輯:

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

(請注意,你可能需要調整循環迭代的次數,給你自己的電腦上合理的延遲)

+1

我相信這樣的改變會直接導致DOM,但瀏覽器會等待,直到JavaScript執行「空閒」,然後再進行重新繪製。 – pimvdb 2012-03-23 10:58:48

+0

「做一些長時間運行的處理」有一些異步調用? (ajax,settimeout等) – 2012-03-23 11:00:31

+0

我不能真正看到你的代碼出錯了,因爲它看起來很好,你已經發布。也許在你的外部css文件中有一些'!important'。你確定增加了班級(你是否通過螢火蟲檢查過),這個過程真的需要很長時間嗎?可能它發生得太快 – 2012-03-23 11:00:44

回答

0

Force a redraw。或者,使用Soren's code,因爲UI線程上的處理聽起來很糟糕...

+0

但是,jQuery插件似乎目前處於關閉狀態。增加了一個替代品這可能是因爲你不需要推遲'n.parentNode.removeChild(n)';如果是這樣,請隨時編輯我的答案。 – 2012-03-23 11:57:09

+0

我在我的jsFiddle上嘗試過這個,但沒有成功。我顯然沒有正確使用它。你可以加小提琴嗎? – njr101 2012-03-23 13:00:54

+0

對不起,但小提琴不起作用。該類將被應用,然後腳本會以腳本錯誤中止。 「完成」消息從不顯示。 – njr101 2012-03-23 14:17:15

1

我不建議凍結重量腳本的瀏覽器。 在這種情況下,我更喜歡更改不凍結瀏覽器和DOM的代碼。 如果在你的代碼中有一些循環,你可以使用延遲調用一個函數(使用setInterval)並在某處存儲一些狀態變量。 例如:

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

可以是:

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

或類似和更優化的東西。 你的代碼會更復雜一點,而且速度更慢。但是這樣可以防止瀏覽器凍結,並且可以創建高級預加載狀態欄。

+0

謝謝,這就是我提到'setTimeout'時的意思。我意識到我可以做到這一點,但我希望避免增加異步調用的複雜性。當異步回調發生時,狀態不確定會打開一整類其他問題。 – njr101 2012-03-23 12:50:04

+0

我知道。你也可以看到網絡工作者http://www.html5rocks.com/en/tutorials/workers/basics/ – 2012-03-23 12:52:57

+0

感謝您的鏈接。有趣的東西,但不幸的是不會幫助我,因爲我需要跨瀏覽器支持。 – njr101 2012-03-23 13:17:36

1

你可能應該把處理放在一個單獨的事件中,像這樣;

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

這樣的瀏覽器應重繪屏幕與processing,而長跑步步揭開序幕,作爲一個單獨的事件,並在完成後刪除處理消息。

+0

謝謝,這是我懷疑。我真的希望有一種方法可以避免瀏覽器在更改DOM後重新呈現此強制。 – njr101 2012-03-23 14:20:36

+0

警告 - 我發現它在5ms超時後開始工作 - 任何更短和鉻仍然等待。 – user2486570 2016-12-11 21:22:56

+0

@ user2486570 - 我懷疑它 - JS是單線程事件循環 - 所以它只有你自己創建的競爭條件 - 如果你看到一個5ms的問題可能是因爲你有別的東西運行一個計時器或一個與您的其他代碼衝突的DOM就緒事件。 – Soren 2016-12-11 21:28:59

0

瀏覽器對於何時重新繪製以及何時迴流是非常自由的。不同的引擎會顯示不同的行爲。有關進一步閱讀,請參閱When does reflow happen in a DOM environment?。在你的例子中,瀏覽器會看到你添加了一個類,然後直接刪除它,所以他可能不會做任何可見的事情。爲了避免這種情況,你可以應用一個強制重畫黑客攻擊,或者使你的計算與WebWorkers或setTimeout等進行異步處理。