http://jsfiddle.net/Codemonkey/ye5qv/2/
我正在尝试使用setInterval编写大型工作负载,以便浏览器可以在每次迭代工作之间捕获它。在上面的例子中,我给浏览器在斐波那契计算的每个间隔之间休息了100毫秒,但是从调用fib()
的那一刻起到调用回调的那一刻,浏览器仍然处于冻结状态。 注意:在我的示例中,在文档加载后一秒钟之前没有调用fibo函数,因此您可以清楚地看到它冻结几秒钟
究竟为什么这种方法不起作用,我怎样才能使它工作?或者,哪种其他方法可以达到相同的目标结果?重申一下,使用setInterval拆分工作的目的是浏览器在此过程中 永远不会 冻结或编译器。
我正在使用Chrome,我主要关注的是V8引擎,但x-browser兼容的解决方案是一个奖励
答案 0 :(得分:4)
不幸的是,JavaScript setInterval
和setTimeout
并非真正异步,因此所有内容仍将在单个线程中运行。这意味着当调用setInterval
回调时,它会在主线程中运行并阻止其他所有内容的执行。
以下是John Resig的精彩文章,详细讨论了这一点:How JavaScript Timers Work。
如果您想要真正的异步JavaScript,则必须使用类似Web Workers的内容。
正如其他人在此指出的那样,在你的特定情况下,你实际上在这一行上有一个无限循环:
for(var i = start; i < i+workload; i++)
导致您的代码:
setTimeout(function() {
processor(start + workload);
}, 100);
永远不会被召唤。有关详细信息,请参阅Guffa's excellent answer。
我的答案的其余部分仍然适用 - 如果您尝试做的不仅仅是简单的操作,同时为.gif
设置动画,您可能仍然会在没有像Web Workers这样的东西的情况下冻结或口吃。
答案 1 :(得分: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);
答案 2 :(得分:1)
我注意到你的代码中setInterval
实际上从未被调用过,因为在这行中
for(var i = start; i < i+workload; i++)
条件始终为真,因为i
始终小于i+workload
,因此它永远不会离开循环。从循环内部的函数返回的好东西。