setInterval会导致浏览器挂起吗?

3

几年前,有人警告我不要在长时间内使用setInterval,因为如果被调用的函数运行时间超过指定的间隔,它会导致浏览器挂起,并且无法赶上运行:

setInterval( function(){
  foo = 'bar_' + i++;
}, 1 );

我知道在循环中添加大量代码可能会导致浏览器挂起,而像 alertpromptconfirm 这样的阻塞代码会停止代码执行,但是有没有什么好的理由避免使用 setInterval

注意:我知道如何使用递归的 setTimeout 调用(因为我一直在使用它),这个问题是我试图弄清楚是否仍然值得使用它们,或者是否可以安全地使用 setInterval


Chrome在使用setInterval时存在问题。请参见此处:http://code.google.com/p/chromium/issues/detail?id=25892。个人而言,我只是使用递归的setTimeout(闭包非常适用于此)。 - user1385191
2个回答

21

setInterval的问题在于它会尝试每X毫秒执行一次代码,而不考虑线程中正在发生什么。所以如果你有:

setInterval( complexFunction, 1 ); // complexFunction takes >1 MS to complete

如果你使用 setInterval,可能会出现在代码完成之前多次尝试重新执行的情况!然而,你可以使用类似的 setTimeout 并避免这个问题:

setTimeout( complexFunction, 1 );

function complexFunction() {
  // complex code
  setTimeout( complexFunction, 1 );
}

现在complexFunction函数只有在自身的代码执行完毕后才会再次调用自身,所以如果它自己的代码执行需要超过1毫秒,你就不必像使用setInterval时那样处理未完成的任务。


这正是我听到的相同信息。是否有任何来源或演示代码来证明这仍然是一个问题? - zzzzBov
这取决于代码的复杂性和需要考虑的浏览器速度。您可以随时尝试将任何V8基准测试(http://v8.googlecode.com/svn/data/benchmarks/v3/run.html)放入1毫秒重复的setInterval中,看看它会如何糟糕地崩溃。 - mVChr
5
这是绝对错误的。如果浏览器在两次间隔到期之间一直处于繁忙状态,则间隔调用会被丢弃,而不是排队等待执行。请参阅示例 - josh3736
2
我知道这是一个旧的帖子,但我想指出我在使用ajax请求进行间隔时遇到了这个问题。我通过使用超时并嵌套调用来解决它,以便当最终调用解决时重置超时。在桌面上没有问题,但在平板电脑上(非常糟糕的平板电脑)遇到了问题。 - Mitchell Ingram
这段代码在无限递归的情况下,长时间运行后是否会耗尽所有的机器资源,例如堆栈内存? - Vladyslav Nikolaiev

-1

在循环中最好使用setTimeout,这样你就知道何时继续计时:

foo();
function foo(){

   setTimeout (function(){
      foo = 'bar_' + i++;
      foo();
     }, 1 );

} 

否则如上所述,浏览器将不得不 catch up,而由于您的循环是无限的,它可能无法进行。

1
这是完全不正确的。如果浏览器在间隔时间到期两次期间一直处于繁忙状态,则间隔调用会被丢弃,而不是排队等待;因此浏览器不会尝试“赶上”。请参见示例。 - josh3736
@josh3736 你甚至看了一下你的脚本吗???!你在十秒后清除了间隔! - Naftali
3
如果它们被删除,您将在旋转号码中看到1、3、5等。你的操作并没有证明什么。 - Florian Margaine
@FlorianMargaine:不,这个小提琴计算的是spin被调用的次数,而不是应该经过多少个时间间隔。它不应该计算奇数。 - josh3736
@Neal:为了演示的目的,我们必须停止旋转。你可以很容易地制作一个按钮来清除间隔,而不是设置一个超时来清除它。 - josh3736
更多阅读,请参见John Resig的JavaScript计时器工作原理 - josh3736

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接