setTimeout 还是 setInterval?

2022-08-29 22:27:15

据我所知,这两段javascript的行为方式相同:

备选案文A:

function myTimeoutFunction()
{
    doStuff();
    setTimeout(myTimeoutFunction, 1000);
}

myTimeoutFunction();

备选案文B:

function myTimeoutFunction()
{
    doStuff();
}

myTimeoutFunction();
setInterval(myTimeoutFunction, 1000);

使用 setTimeoutsetInterval 之间有什么区别吗?


答案 1

他们基本上试图做同样的事情,但方法将比方法更准确,因为等待1000ms,运行函数,然后设置另一个超时。因此,等待时间实际上略大于1000ms(如果您的函数需要很长时间才能执行,则等待时间会更长)。setIntervalsetTimeoutsetTimeout

虽然有人可能认为它将恰好每1000ms执行一次,但重要的是要注意,这也将延迟,因为JavaScript不是一种多线程语言,这意味着 - 如果有脚本的其他部分正在运行 - 间隔将不得不等待它完成。setIntervalsetInterval

在这个小提琴中,您可以清楚地看到超时将落后,而间隔几乎一直都在1次调用/秒(脚本正在尝试这样做)。如果将顶部的速度变量更改为 20 这样的小变量(这意味着它将尝试每秒运行 50 次),则间隔永远不会达到平均每秒 50 次迭代。

延迟几乎总是可以忽略不计,但是如果你正在编程一些非常精确的东西,你应该选择一个自我调整的计时器(它本质上是一个基于超时的计时器,它不断调整自身以产生延迟)


答案 2

有什么区别吗?

是的。超时在调用 setTimeout() 后执行一定时间;间隔在上一个间隔触发后执行一定时间。

如果您的 doStuff() 函数需要一段时间才能执行,您会注意到差异。例如,如果我们用 来表示对 setTimeout/setInterval 的调用,则使用 和 JavaScript 代码执行的触发,时间线如下所示:.*[-----]

Timeout:

.    *  .    *  .    *  .    *  .
     [--]    [--]    [--]    [--]

Interval:

.    *    *    *    *    *    *
     [--] [--] [--] [--] [--] [--]

下一个复杂情况是,如果一个间隔触发,而JavaScript已经忙于做某事(例如处理以前的间隔)。在这种情况下,将记住间隔,并在上一个处理程序完成并将控制权返回给浏览器后立即发生。例如,对于有时很短([-])有时很长([-])的doStuff()进程([-----]):

.    *    *    •    *    •    *    *
     [-]  [-----][-][-----][-][-]  [-]

• 表示无法立即执行其代码的间隔触发,而是将其设置为挂起。

因此,间隔时间试图“赶上”以按计划返回。但是,它们不会将一个队列在彼此之上:每个间隔只能有一个执行挂起。(如果它们都排队,浏览器将留下一个不断扩大的未完成执行列表!

.    *    •    •    x    •    •    x
     [------][------][------][------]

x 表示无法执行或挂起的间隔触发,因此被丢弃。

如果您的 doStuff() 函数习惯性地执行时间长于为其设置的时间间隔,则浏览器将占用 100% 的 CPU 来尝试为其提供服务,并且可能会变得响应速度降低。

你使用哪个,为什么?

链超时为浏览器提供了有保证的空闲时间;间隔尝试确保它正在运行的函数尽可能接近其计划时间执行,但以牺牲浏览器 UI 可用性为代价。

我会考虑一个一次性动画的间隔,我希望尽可能流畅,而链接的超时对于在页面加载时一直发生的正在进行的动画来说更礼貌。对于要求较低的用途(例如每 30 秒触发一次简单的更新程序或其他用途),您可以安全地使用其中任何一个。

在浏览器兼容性方面,setTimeout 早于 setInterval,但您今天遇到的所有浏览器都支持这两种功能。多年来的最后一个流浪者是WinMo<6.5的IE Mobile,但希望现在这也已经过去了。