当我的扩展程序开始繁重的工作(for
循环将触发更多进程时),Firefox停止响应。在我的分机完成工作之前,它不会恢复工作。
我的扩展需要大约16000毫秒才能完成其工作。有没有办法异步执行我的脚本?或者还有其他方法可以解决这个问题吗?
答案 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的函数的提议,这个函数用于这个目的 - 但是大多数浏览器还没有实现它。