2012-02-28 17 views
4

我的一頁頁面中有9000個元素,需要經常重建,這可能需要幾秒鐘的時間。DOM更新後跟一個大循環不能及時呈現

所以,我做了一個小覆蓋小部件,覆蓋與Loading..元素。信息。在我重建元素之前,我打電話給showOverlay(),在循環之後我打電話給hideOverlay()

但是,在顯示我的Loading...消息之前,循環會鎖定頁面,因此它永遠不會顯示。

function rebuild() { 
    showOverlay(); // The overlay never appears... 
    for (var i=0;i<9000;i++) { 
    // append element... 
    } 
    hideOverlay(); 
} 

如何等待疊加層在我開始循環之前呈現?

回答

3
function do_rebuild() { 
    for (var i=0;i<9000;i++) { 
    // append element... 
    } 
    hideOverlay(); 
} 


function rebuild() { 
    showOverlay(); // The overlay will appear 
    window.setTimeout('do_rebuild();',1); 
} 

是我所知道的唯一的跨瀏覽器方式。

+0

爲1毫秒保證夠嗎? – 2012-02-28 22:32:24

+0

@TonyR它不應該花很長時間,但我會把它設置爲10. IIRC谷歌瀏覽器將只使用至少10個,所以如果你有它在1ms它仍然會等待。 10毫秒。這仍然會凍結頁面。 – 2012-02-28 22:36:16

+0

不需要多長時間 - 1ms可能夠用了。重要的部分是強制類似於「線程切換」的東西(即使它不是以普遍接受的方式表示的線程切換) - brwoser將放置JS任務並啓動DOM任務,超時將不會打斷,但被延遲。 – 2012-02-28 22:41:37

1

你需要把你的循環放在設置的超時時間內,這樣它纔不會佔據頁面。即使顯示您的覆蓋,沒有人喜歡自己的網頁凍結

var counter = 0; 
function rebuild() { 
    showOverlay(); 
    doWork(); 
} 
function doWork() { 
    if(counter < 9000){ 
     // append element 
     counter++; 
     setTimeout(function(){ 
      doWork(); 
     },10); 
    } 
    else { 
     hideOverlay(); 
    } 
} 

編輯:這個答案實際上將顯著需要更長的時間來處理,雖然頁面。在90秒的時間裏,這是非常不可接受的,另一種選擇是每100次迭代設置一次超時,這將增加總負載時間約1秒,但應該停止頁面凍結。

function doWork() { 
    if(counter < 9000){ 
     // append element 
     if(counter % 100 == 0) { 
      setTimeout(function(){ 
       doWork(); 
      },10); 
      counter++; 
     } 
     else { 
      doWork(); 
      counter++; 
     } 
    } 
    else { 
     hideOverlay(); 
    } 
} 
+0

這是不是隻是延遲整個事情10毫秒?對我來說,仍然有一個9000循環的循環。 – 2012-02-28 22:36:24

+0

哦,我現在看到了,在開始下一步之前,它給出了先前的迭代10毫秒...嗯,我會嘗試它! – 2012-02-28 22:38:29

+0

是的,嘗試我的第二個,那第一個將永遠佔用。 – 2012-02-28 22:41:24

0

其他答案顯示瞭如何使用定時器以「僞線程」方式執行此操作。

與此同時,我已經瞭解了Web Workers,這是一個將腳本執行與DOM更新分開的線程解決方案。

他們目前支持WebKit和Firefox和支持計劃在IE 10

+0

Web工作人員無權訪問DOM。解決方案很好,但我擔心,它不適合這個問題。 – 2014-03-23 17:54:44

0

你可以試試這個:

var loopCount = 0, 
    build = function() { 

    var frgm = document.createDocumentFragment(); 
    for (var i = 0; i < 200 && loopCount < 9000; i++) { 
     // some codes 
     frgm.appendChild(someElement); 
     loopCount ++; 
    } 
    parentNode.appendChild(frgm); 

    if (loopCount < 9000) { 
     setTimeout(build, 10); 
    } 
}; 

function rebuild() { 
    showOverlay(); // The overlay never appears... 
    build(); 
    hideOverlay(); 
}