简体   繁体   English

为什么用setTimeout分割的工作负载仍然冻结浏览器?

[英]Why does a workload split up by setTimeout still freeze the browser?

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

I am experimenting with writing large workloads to recur using setInterval so that the browser can catch it's breath between each iteration of work. 我正在尝试编写大型工作量以使用setInterval进行重现,以使浏览器可以在每次工作迭代之间呼吸一下。 In my example above I'm giving the browser 100ms of rest between each interval of fibonacci calculations, but the browser is still frozen from the moment fib() is called to the moment the callback is called. 在上面的示例中,我给浏览器在fibonacci计算的每个间隔之间有100毫秒的休息时间,但从调用fib()到调用回调的那一刻,浏览器仍然处于冻结状态。 Note: In my example, the fibo function isn't called before one second after the document load so you can clearly see it freeze for a few seconds 注意:在我的示例中,fibo函数在文档加载后一秒钟没有调用,因此您可以清楚地看到它冻结了几秒钟

Exactly why isn't this method working, and how can I make it work? 究竟为什么这种方法不起作用,如何使它起作用? Alternatively, which other method could achieve the same goal result? 或者,哪种其他方法可以达到相同的目标结果? To reiterate, the goal of using setInterval to split up the work is that the browser should never freeze or studder during the process. 重申一下,使用setInterval拆分工作的目标是,浏览器在此过程中切勿冻结或散布。

I'm using chrome and I'm mainly concerned with the V8 engine, but an x-browser compatible solution is a bonus 我使用的是chrome,主要关注V8引擎,但是与x浏览器兼容的解决方案是一个不错的选择

Unfortunately, JavaScript's setInterval and setTimeout aren't truly asynchronous, so everything will still operate in a single thread. 不幸的是,JavaScript的setIntervalsetTimeout并非真正异步,因此所有内容仍将在单个线程中运行。 That means that when your setInterval callback is called, it runs in the main thread and blocks execution of everything else. 这意味着,当调用setInterval回调时,它将在主线程中运行,并阻止其他所有事件的执行。

Here is a great post by John Resig which discusses this in detail: How JavaScript Timers Work . 这是John Resig撰写的精彩文章,详细讨论了这一点: JavaScript计时器的工作原理

If you want truly asynchronous JavaScript, you must use something like Web Workers . 如果要使用真正的异步JavaScript,则必须使用Web Workers之类的东西。


As others have pointed out here, in your particular case you actually have an infinite loop on this line: 正如其他人在这里指出的那样,在您的特定情况下,您实际上在此行上有一个无限循环:

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

Which is causing your code: 这是导致您的代码的原因:

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

To never be called. 永不被呼唤。 See Guffa's excellent answer for more information. 有关更多信息,请参见Guffa的出色答案

The rest of my answer still does apply though- if you're trying to do more than simple operations and animating a .gif simultaneously you may still have freezing or stuttering without using something like Web Workers. 我的答案的其余部分仍然适用-如果您尝试做的不仅仅是简单的操作,并且同时给.gif动画设置动画,那么您可能仍然会冻结或卡顿,而没有使用Web Workers之类的东西。

The problem is that your code never reaches the point where it calls setTimeout to give control back to the browser. 问题是您的代码永远不会到达调用setTimeout来将控制权交还给浏览器的地步。

Change this: 更改此:

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

to: 至:

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

As workload is a positive number, i < i + workload will never be false, so you have an infinite loop. 由于workload为正数,因此i < i + workload永远不会为假,因此您将陷入无限循环。


You don't have to wait for 100 ms when giving control back to the browser, just calling setTimout is enough to make the browser handle events, so you can use the time 0: 将控制权交还给浏览器时,您不必等待100 ms,只需调用setTimout就足以使浏览器处理事件,因此可以使用时间0:

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

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

I noticed that in your code setInterval is actually never called, because in this line 我注意到在您的代码中setInterval实际上从未被调用,因为在这一行

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

the condition is always true since i is always smaller than i+workload , so it will never get out of the cycle. 该条件始终为真,因为i总是小于i+workload ,因此它永远不会超出周期。 Good thing that you return from the function inside the loop. 从循环内部的函数返回的好东西。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM