2012-12-17 37 views
0

我想在頁面上持續執行一段JavaScript代碼,花費所有可用的CPU時間,但可以讓瀏覽器正常工作並響應同一時間。遏制網頁上JavaScript連續執行的最有效方法

如果我只是不斷運行我的代碼,它會凍結瀏覽器的UI,並且瀏覽器開始抱怨。現在我通過一個零超時到setTimeout,然後做一小塊工作,並循環回setTimeout。這工作,但似乎並沒有利用所有可用的CPU。有什麼更好的方法可以做到這一點?

更新:更具體地說,所討論的代碼是連續渲染幀canvas。這裏的工作單位是一個框架。我們的目標是儘可能提高幀率。

+0

這是因爲大多數瀏覽器不允許0ms的JavaScript間隔。他們在20ms或者類似的東西上限。 –

+0

這似乎是一個非常糟糕的主意,但也許不適合你的目的。你能告訴我們你正在運行的代碼是不是在做什麼? – hobberwickey

+0

@hobberwickey:它在畫布上渲染圖形,旨在獲得最高的幀速率。 – dragonroot

回答

0

可以使用window.postMessage()來克服對最小時間量setTimeout強制執行的限制。有關詳細信息,請參見this article。演示可用here

2

網絡工作者有一些嘗試

https://developer.mozilla.org/en-US/docs/DOM/Using_web_workers 
+0

謝謝!這可能適用 - 但是,代碼正在頁面上繪製,這可能不是工作人員可以做的。我希望工作人員必須將所有結果傳遞給UI線程,這會爲程序員和瀏覽器增加額外的工作量。 – dragonroot

3

也許你想要的是集中在頁面上發生的一切,並使用requestAnimationFrame做所有的繪圖。所以基本上你將有一個函數/類,它看起來像這樣(你必須原諒我用MooTools的類中的某些風格/語法錯誤,只是以此爲輪廓)

var Main = function(){ 
    this.queue = []; 
    this.actions = {}; 

    requestAnimationFrame(this.loop) 
} 

Main.prototype.loop = function(){ 
    while (this.queue.length){ 
     var action = this.queue.pop(); 
     this.executeAction(e); 
    } 

    //do you rendering here 
    requestAnimationFrame(this.loop); 
} 

Main.prototype.addToQueue = function(e){ 
    this.queue.push(e); 
} 

Main.prototype.addAction = function(target, event, callback){ 
    if (this.actions[target] === void 0) this.actions[target] = {}; 
    if (this.actions[target][event] === void 0) this.actions[target][event] = []; 

    this.actions[target][event].push(callback); 
} 

Main.prototype.executeAction = function(e){ 
    if (this.actions[e.target]!==void 0 && this.actions[e.target][e.type]!==void 0){ 
     for (var i=0; i<this.actions[e.target][e.type].length; i++){ 
      this.actions[e.target][e.type](e); 
     } 
    } 
} 

所以基本上你會使用這個類來處理頁面上發生的所有事情。每個事件處理程序都是onclick='Main.addToQueue(event)',或者您希望將事件添加到頁面中,您只需指出它們將事件添加到提示中,然後使用Main.addAction將這些事件指向您希望他們執行的任何操作。通過這種方式,只要畫布完成重繪並在重繪之前,每個用戶動作都會被執行。只要您的畫布呈現出體面的幀率,您的應用應該保持響應。

編輯:忘了「本」在requestAnimationFrame(this.loop)

+0

謝謝。但你有沒有提到'onclick'?我是否必須始終讓用戶點擊頁面上的所有內容才能使代碼前進?我不太明白如何以及何時在那裏實際執行代碼。我需要網頁在沒有任何用戶交互的情況下運行 - 用戶只是坐在後面觀看。 – dragonroot

+0

對,你把動畫渲染代碼放在我指出的地方,如果你想要發生其他事情(比如用戶點擊事物,或者他們會在頁面上做的任何事情),你可以使用addToQueue來觸發它們。如果用戶沒有做任何動作,只是播放動畫。 – hobberwickey

+0

是的,但是什麼重新觸發動畫?也就是說,在渲染完一幀後,我們需要停下來(所以瀏覽器可以處理UI等)。之後,我們希望被調用來渲染另一個框架 - 會觸發該調用的是什麼? – dragonroot

1

您可以調整,通過改變工作你每次調用做量你的表現。在你的問題中,你說你做了一小部分工作。建立一個參數來控制正在完成的工作量並嘗試各種值。

您也可以嘗試在之前設置超時進行處理。這樣處理所花的時間應該計入瀏覽器設置的最小值。

我使用的一種技術是在我的處理循環中計數迭代計數器。然後在該函數中設置一個時間間隔,比如說一秒,顯示計數器並將其清零。這提供了一個粗略的性能值,可用來衡量您所做更改的效果。

一般來說,這可能非常依賴於特定的瀏覽器,甚至是瀏覽器的版本。通過可調參數和性能測量,您可以實現反饋迴路以實時優化。

+0

謝謝,這是另一種解決方案。這裏最困難的部分是這需要校準。用戶機器上的負載可能隨時間而改變,這會使得這種校準變得脆弱。此外,理想情況下,我只渲染一幀,然後讓瀏覽器處理其事件,然後立即渲染另一幀,等等。也就是說,這裏的工作單位是一個框架 - 很難讓這個單元變得更小或更大。 – dragonroot

+0

確實,你明白困難。我會添加一個參數來控制每個調用的幀數。問題在於每幀的相對處理時間與瀏覽器在無所事事時所花費的時間。這顯然取決於多種因素,其中一些因素可能會不斷變化。 – HBP

相關問題