2010-04-07 56 views
7

我有一個很長的JavaScript函數,它執行許多任務,我想通過在發送消息時更新SPAN元素的內容來向用戶報告進度。我試圖在函數代碼中添加document.getElementById('spnProgress')。innerText = ...語句。如何報告JavaScript函數的進度?

但是,雖然函數正在執行,UI將不會更新,因此您只能看到寫入SPAN的最後一條消息,這不是很有用。

我目前的解決方案是將任務分解成若干功能,每個功能結束時我設置SPAN消息,然後用一個非常短的延遲調用window.setTimeout調用「觸發」下一個函數10毫秒)。這會產生控制權並允許瀏覽器在開始下一步之前用更新的消息重新繪製SPAN。

但是,我覺得這非常混亂,難以遵循代碼,我認爲必須有更好的方法。有沒有人有什麼建議?有沒有辦法強制SPAN重繪,而不必離開函數的上下文?

感謝

回答

7

你這樣做的方式是正確的方式(目前,這可能會改變,因爲標準的出現和採用[見安德魯·艾利特的answer],但沒一會兒還)。你必須這樣做才能允許瀏覽器進行UI更新。我發現,我越是認爲這樣,更清潔的東西就會得到,但是我的第一個嘗試做這件事確實很「雜亂」。希望你找到適合你的相同的東西。

+0

這是正確的選擇。 – Kangkan 2010-04-07 12:32:09

0

這就像詢問是否可以在不中斷程序的情況下中斷程序一樣。答案是不。您必須使用setTimeout()或setInterval()將控制傳遞給瀏覽器的渲染引擎。

如果使用setInterval(),則可以使該進程進行並在執行函數中更新外部變量,該外部變量將由setInterval()調用的函數進行輪詢。這樣你只需要打一個電話,而不是在一個循環中進行。

0

不是我所知道的。你可以打破你的代碼中,使得各個功能可以共享變量的方式,即:

var a = some_local_state(); 
runTasksWithProgress([ 
    function() { 
     do_some_work(a); 
     a = a + 1; 
    }, 
    function() { 
     do_some_other_work(a); 
     a = a * 2; 
    }, 
    ... 
    ]); 

runTasksWithProgress是有點棘手。您基本上會調用第一個任務,更新狀態,然後設置回調以運行後續任務。

這種方法可能會減輕一些痛苦。

2

您需要注意的是,在某些瀏覽器中,如果您有長時間運行的腳本,您將收到腳本超時消息。所以實際上需要使用定時器來分割它。說了這麼多,如果你正在尋找一個真正的結構化的方式,那麼你可以看看我爲拼寫檢查項目編寫的後臺任務庫。它允許您對定時器上的數據數組實施map/reduce。如果你的函數的工作是在一個循環中執行

https://github.com/jameswestgate/taskjs

+0

有關腳本超時的+1好處。 – 2010-04-07 12:35:19

0

這樣的事情可能工作。 它檢查已經過去的時間量,並在1/2秒過去時更新進度條。 (這個例子沒有經過測試,所以你可能需要玩一下。)

var start; 
function longRunning(lastState){ 
    start = (new Date); 
    for(var i = lastState; i < 1e6 /*= 1000000 iterations */; ++i){ 
     if((new Date)-start<500){ 
      // do your stuff; 
     } 
     else{ 
      // call a function to update the progress bar 
      updateProgressBar(); 
      // continue the loop... 
      setTimeout(function(){longRunning(i);},13); 
      break; 
     } 
    } 

} 
longRunning(0); 
3

如果你有目標瀏覽器的控制,你可以使用一個HTML5 worker thread做這項工作的背景。