Firefox在繁重的for循环期间挂起

时间:2011-12-30 14:10:20

标签: javascript firefox-addon

当我的扩展程序开始繁重的工作(for循环将触发更多进程时),Firefox停止响应。在我的分机完成工作之前,它不会恢复工作。

我的扩展需要大约16000毫秒才能完成其工作。有没有办法异步执行我的脚本?或者还有其他方法可以解决这个问题吗?

1 个答案:

答案 0 :(得分:4)

TL; DR:是的,有办法。使用setTimeout使代码在短迭代中运行并产生。

JavaScript中没有线程。好的,是的,有Worker API。但我仍然认为线程是不必要的和邪恶的(竞争条件,死锁等等 - 它已经被覆盖过了)。浏览器扩展可能是JavaScript中的线程可能具有任何优点的唯一用例。但它仍然是最好的避免。

因此。如果不是线程,那么呢? JavaScript有一个事件循环,这是一个诅咒和祝福。每次运行一段代码时,页面上的所有其他内容都会停止(这就是页面无响应的原因)。为了防止这种情况发生,您应该尽可能快地运行代码的每一段,然后 yield 到事件队列中的其他事件。

为此,请使用通过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的函数的提议,这个函数用于这个目的 - 但是大多数浏览器还没有实现它。