1

http://jsfiddle.net/Codemonkey/ye5qv/2/

我正在尝试使用 setInterval 编写大型工作负载以重复使用,以便浏览器可以在每次工作迭代之间呼吸。在上面的示例中,我在每个斐波那契计算间隔之间为浏览器提供 100 毫秒的休息时间,但是从fib()调用到回调调用的那一刻,浏览器仍然处于冻结状态。注意:在我的示例中,fibo 函数在文档加载后一秒之前不会被调用,因此您可以清楚地看到它冻结了几秒钟

究竟为什么这种方法不起作用,我怎样才能使它起作用?或者,还有哪些其他方法可以达到相同的目标结果?重申一下,使用 setInterval 拆分工作的目标是浏览器在此过程中永远不应该冻结或停止。

我正在使用 chrome,我主要关心 V8 引擎,但与 x 浏览器兼容的解决方案是一个奖励

4

3 回答 3

4

setInterval不幸的是,JavaScriptsetTimeout并不是真正的异步,所以一切仍将在单个线程中运行。这意味着当您的setInterval回调被调用时,它会在主线程中运行并阻止其他所有内容的执行。

这是 John Resig 的一篇很棒的文章,详细讨论了这一点:JavaScript 计时器的工作原理

如果你想要真正的异步 JavaScript,你必须使用Web Workers 之类的东西。


正如其他人在这里指出的那样,在您的特定情况下,您实际上在这条线上有一个无限循环:

for(var i = start; i < i+workload; i++)

这导致您的代码:

setTimeout(function() {
    processor(start + workload);
}, 100);

永远不会被召唤。有关更多信息,请参阅Guffa 的出色答案

不过,我的其余答案仍然适用 - 如果您尝试做的不仅仅是简单的操作并.gif同时为 a 设置动画,那么在不使用 Web Workers 之类的东西的情况下,您可能仍然会出现冻结或口吃。

于 2012-06-08T12:34:44.107 回答
4

setTimeout问题是您的代码永远不会到达它调用以将控制权交还给浏览器的地步。

改变这个:

for(var i = start; i < i+workload; i++)

到:

for(var i = start; i < start+workload; i++)

因为workload是正数,i < i + workload永远不会是假的,所以你有一个无限循环。


将控制权交还给浏览器时不必等待 100 毫秒,只需调用setTimout即可使浏览器处理事件,因此可以使用时间 0:

setTimeout(function() {
  processor(start + workload);
}, 0);

演示:http: //jsfiddle.net/Guffa/ye5qv/3/

于 2012-06-08T12:40:03.570 回答
1

我注意到在您的代码setInterval中实际上从未调用过,因为在这一行中

for(var i = start; i < i+workload; i++)

条件始终为真,因为i它总是小于i+workload,所以它永远不会脱离循环。从循环内的函数返回的好事。

于 2012-06-08T12:39:42.680 回答