2011-12-30 56 views
1

當我的擴展開始繁重的工作(for循環會觸發更多進程)時,Firefox停止響應。在我的擴展完成工作之前,它不會恢復工作。Firefox在循環中掛起

我的擴展需要大約16000毫秒來完成其工作。有沒有辦法異步執行我的腳本?還是有其他方法可以解決這個問題嗎?

+1

您是否考慮過[使用網絡工作者](https://developer.mozilla.org/En/Using_web_workers)? – Pierre 2011-12-30 15:30:45

回答

4

TL; DR:是的,有一種方法。讓您的代碼在短時間內運行並使用setTimeout生成。

JavaScript中沒有線程 。好的,是的,有Worker API。但我仍然認爲線程是不必要的,也是邪惡的(競爭條件,僵局等等 - 它們之前都被覆蓋了)。瀏覽器擴展可能是JavaScript中的線程可能具有任何優點的唯一用例。但它仍然是最好的避免。

所以。如果不是線程,那麼呢? JavaScript有一個事件循環,這是一個詛咒和祝福。每次運行一段代碼時,頁面上的所有其他內容都會暫停(這就是頁面無響應的原因)。爲防止這種情況發生,您應該儘可能快地運行代碼的每一部分,然後產生到事件隊列中的其他事件。

爲此,請使用遞歸函數替換for循環,該函數通過setTimeout自行調用。因此,而不是這樣的:

var length = collection.length; // <-- 2 gazillion 
var i; 
for (i=0; i<length; i+=1) { 
    lengthyOperation(i); 
} 
// Script yields here. 

...你會做這樣的事情:

var length = collection.length; // <-- still 2 gazillion 
var i; 
function lengthyOperationAsync() { 
    lengthyOperation(i); // <-- still lengthy 
    i += 1; 
    if (i < length) { 
     setTimeout(lengthyOperationAsync, 0); 
    } 
    // Script yields here. 
} 

這樣,瀏覽器就可以更新頁面,在你漫長的for的迭代之間處理用戶輸入循環。只有一個缺點:在某些瀏覽器中可能需要比平常更長的時間。這是因爲timer resolution;某些瀏覽器在使用setTimeout時的最小延遲爲4ms,即使您指定0

順便說一下,有一個叫做setImmediate的函數的提議,這是爲了這個確切的目的 - 但大多數瀏覽器還沒有實現它。

+2

誰可以投下這個請[請解釋爲什麼](http://stackoverflow.com/faq#behonest)? – PPvG 2011-12-30 15:41:55

+0

這不是我,但我的猜測會是因爲你暗示網絡工作者不存在,這幾乎完全是要求的,無論是否適合解決他的問題。 – goat 2011-12-30 15:51:26

+0

@chris:謝謝你指出。你也許是對的。我已經修改了答案以避免混淆。 – PPvG 2011-12-31 00:46:53