當我的擴展開始繁重的工作(for
循環會觸發更多進程)時,Firefox停止響應。在我的擴展完成工作之前,它不會恢復工作。Firefox在循環中掛起
我的擴展需要大約16000毫秒來完成其工作。有沒有辦法異步執行我的腳本?還是有其他方法可以解決這個問題嗎?
當我的擴展開始繁重的工作(for
循環會觸發更多進程)時,Firefox停止響應。在我的擴展完成工作之前,它不會恢復工作。Firefox在循環中掛起
我的擴展需要大約16000毫秒來完成其工作。有沒有辦法異步執行我的腳本?還是有其他方法可以解決這個問題嗎?
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的函數的提議,這是爲了這個確切的目的 - 但大多數瀏覽器還沒有實現它。
您是否考慮過[使用網絡工作者](https://developer.mozilla.org/En/Using_web_workers)? – Pierre 2011-12-30 15:30:45