793

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

选项 A:

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

myTimeoutFunction();

选项 B:

function myTimeoutFunction()
{
    doStuff();
}

myTimeoutFunction();
setInterval(myTimeoutFunction, 1000);

使用setTimeoutsetInterval有什么区别吗?

4

20 回答 20

692

他们基本上尝试做同样的事情,但这种setInterval方法会比这种setTimeout方法更准确,因为setTimeout等待 1000 毫秒,运行函数,然后设置另一个超时。所以等待时间实际上比 1000 毫秒多一点(如果你的函数需要很长时间才能执行,那么等待时间会更长)。

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

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

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

于 2009-04-08T13:14:46.583 回答
659

有什么区别吗?

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

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

Timeout:

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

Interval:

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

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

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

• 表示无法立即执行其代码的间隔触发,而是处于挂起状态。

因此,间隔尝试“赶上”以恢复进度。但是,它们不会将一个放在彼此之上:每个间隔只能有一个待执行的执行。(如果他们都排队,浏览器会留下一个不断扩大的未完成执行列表!)

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

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

如果你的 doStuff() 函数的执行时间习惯性地比为它设置的时间间隔长,浏览器将消耗 100% 的 CPU 来尝试服务它,并且可能会变得反应迟钝。

你使用哪个,为什么?

Chained-Timeout 为浏览器提供有保证的空闲时间;Interval 尝试确保它正在运行的函数尽可能接近其预定时间执行,但会牺牲浏览器 UI 的可用性。

我会考虑一次性动画的间隔,我希望尽可能平滑,而链接超时对于在页面加载时一直发生的持续动画更礼貌。对于要求不高的用途(例如每 30 秒触发一次的微不足道的更新程序等),您可以安全地使用其中任何一个。

在浏览器兼容性方面,setTimeout 早于 setInterval,但您今天遇到的所有浏览器都支持这两者。多年以来的最后一个落后者是 WinMo <6.5 中的 IE Mobile,但希望它现在也已落后于我们。

于 2009-04-08T20:13:28.137 回答
95

设置间隔()

setInterval()是一种基于时间间隔的代码执行方法,具有在达到间隔时重复运行指定脚本的本机能力。脚本作者不应其嵌套到其回调函数中以使其循环,因为它默认循环。除非您调用clearInterval().

如果要循环动画或时钟滴答的代码,请使用setInterval().

function doStuff() {
    alert("run your code here when time interval is reached");
}
var myTimer = setInterval(doStuff, 5000);

设置超时()

setTimeout()是一种基于时间的代码执行方法,当达到间隔时将只执行一次脚本。不会再次重复,除非您通过将对象嵌套在setTimeout()它调用运行的函数内来使其循环脚本。如果适合循环,除非您调用clearTimeout().

function doStuff() {
    alert("run your code here when time interval is reached");
}
var myTimer = setTimeout(doStuff, 5000);

如果您希望某事在指定时间段后发生一次,请使用setTimeout(). 那是因为它只在达到指定的时间间隔时执行一次。

于 2013-08-14T05:12:32.157 回答
45

setInterval 可以更轻松地取消将来执行代码。如果您使用 setTimeout,则必须跟踪计时器 ID,以防您以后想取消它。

var timerId = null;
function myTimeoutFunction()
{
    doStuff();
    timerId = setTimeout(myTimeoutFunction, 1000);
}

myTimeoutFunction();

// later on...
clearTimeout(timerId);

相对

function myTimeoutFunction()
{
    doStuff();
}

myTimeoutFunction();
var timerId = setInterval(myTimeoutFunction, 1000);

// later on...
clearInterval(timerId);
于 2009-04-08T13:25:24.420 回答
23

setTimeout如果您想取消超时,我发现该方法更易于使用:

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

myTimeoutFunction();

此外,如果函数中出现问题,它将在第一次错误时停止重复,而不是每秒重复一次错误。

于 2009-04-08T14:20:02.760 回答
20

不同之处在于它们的目的。

setInterval()
   -> executes a function, over and over again, at specified time intervals  

setTimeout()
   -> executes a function, once, after waiting a specified number of milliseconds

就这么简单

更详细的细节在这里http://javascript.info/tutorial/settimeout-setinterval

于 2014-01-11T10:16:45.857 回答
16

当您在 setInterval 中运行某些函数时,它的工作时间比超时时间长-> 浏览器将被卡住。

- 例如,doStuff()需要 1500 秒。要执行,然后执行:setInterval(doStuff, 1000);
1) 浏览器运行doStuff()需要 1.5 秒。被执行;
2) 约 1 秒后,它尝试再次运行doStuff()。但是之前的doStuff()仍然执行->所以浏览器将此运行添加到队列中(在第一次完成后运行)。
3,4,..) 相同的添加到下一次迭代的执行队列中,但之前的doStuff()仍在进行中...... 结果 -
浏览器卡住了。

为了防止这种行为,最好的方法是在 setTimeout 中运行setTimeout 来模拟 setInterval
要更正 setTimeout 调用之间的超时,您可以使用自更正替代 JavaScript 的 setInterval技术。

于 2014-04-26T17:42:53.623 回答
10

您的代码将有不同的执行间隔,并且在某些项目中,例如在线游戏,这是不可接受的。首先,你应该怎么做,为了让你的代码使用相同的间隔,你应该将“myTimeoutFunction”更改为:

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

此更改后,它将等于

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

但是,你仍然会得到不稳定的结果,因为 JS 是单线程的。目前,如果 JS 线程忙于某事,它将无法执行您的回调函数,执行将推迟 2-3 毫秒。您是否每秒执行 60 次,并且每次随机延迟 1-3 秒,这绝对是不可接受的(一分钟后延迟约为 7200 毫秒),我可以建议使用这样的东西:

    function Timer(clb, timeout) {
        this.clb = clb;
        this.timeout = timeout;
        this.stopTimeout = null;
        this.precision = -1;
    }

    Timer.prototype.start = function() {
        var me = this;
        var now = new Date();
        if(me.precision === -1) {
            me.precision = now.getTime();
        }
        me.stopTimeout = setTimeout(function(){
            me.start()
        }, me.precision - now.getTime() + me.timeout);
        me.precision += me.timeout;
        me.clb();
    };

    Timer.prototype.stop = function() {
        clearTimeout(this.stopTimeout);
        this.precision = -1;
    };

    function myTimeoutFunction()
    {
        doStuff();
    }

    var timer = new Timer(myTimeoutFunction, 1000);
    timer.start();

此代码将保证稳定的执行周期。甚至线程会很忙,你的代码会在 1005 毫秒后执行,下次它会有 995 毫秒的超时,结果会稳定。

于 2016-12-24T11:32:08.653 回答
9

我使用 setTimeout。

显然不同之处在于 setTimeout 调用该方法一次, setInterval 重复调用它。

这是一篇很好的文章,解释了区别:教程:带有 setTimeout 和 setInterval 的 JavaScript 计时器

于 2009-04-08T13:15:52.290 回答
7

我对 进行了简单的测试setInterval(func, milisec),因为我很好奇当函数时间消耗大于间隔持续时间时会发生什么。

setInterval通常会在前一次迭代开始之后安排下一次迭代,除非函数仍在进行中。如果是这样,setInterval将等待,直到函数结束。一旦发生,该函数会立即再次触发 - 无需根据计划等待下一次迭代(因为它会在没有超时函数的条件下)。也没有并行迭代运行的情况。

我已经在 Chrome v23 上对此进行了测试。我希望它是所有现代浏览器的确定性实现。

window.setInterval(function(start) {
    console.log('fired: ' + (new Date().getTime() - start));
    wait();
  }, 1000, new Date().getTime());

控制台输出:

fired: 1000    + ~2500 ajax call -.
fired: 3522    <------------------'
fired: 6032
fired: 8540
fired: 11048

wait函数只是一个线程阻塞助手 - 同步 ajax 调用,在服务器端需要2500 毫秒的处理时间:

function wait() {
    $.ajax({
        url: "...",
        async: false
    });
}
于 2012-11-25T22:20:23.383 回答
6

setInterval 和 setTimeout 都返回一个计时器 id,您可以使用它来取消执行,即在触发超时之前。要取消,您可以像这样调用 clearInterval 或 clearTimeout:

var timeoutId = setTimeout(someFunction, 1000);
clearTimeout(timeoutId);
var intervalId = setInterval(someFunction, 1000),
clearInterval(intervalId);

此外,当您离开页面或关闭浏览器窗口时,超时会自动取消。

于 2009-04-08T14:47:06.423 回答
6

换个角度来看:setInterval 确保代码以每个给定的时间间隔(即 1000 毫秒,或您指定的时间间隔)运行,而 setTimeout 设置它“等待直到”运行代码的时间。而且由于运行代码需要额外的毫秒,它加起来是 1000 毫秒,因此 setTimeout 会在不精确的时间(超过 1000 毫秒)再次运行。

例如,计时器/倒计时不是使用 setTimeout 完成的,而是使用 setInterval 完成的,以确保它不会延迟并且代码以确切的给定间隔运行。

于 2015-01-27T20:25:28.987 回答
4

当您运行以下 javascript 或检查此JSFiddle时,您可以自己验证 bobince 答案

<div id="timeout"></div>
<div id="interval"></div>

var timeout = 0;
var interval = 0;

function doTimeout(){
    $('#timeout').html(timeout);
    timeout++;
    setTimeout(doTimeout, 1);
}

function doInterval(){
    $('#interval').html(interval);
    interval++;
}

$(function(){
    doTimeout();
    doInterval();
    setInterval(doInterval, 1);
});
于 2014-11-17T21:45:40.587 回答
3

好吧,正如我刚刚了解到的,在一种情况下 setTimeout 更好。我总是使用 setInterval,我在后台运行了半个多小时。当我切换回该选项卡时,幻灯片(使用代码的)变化非常迅速,而不是它应该每 5 秒发生一次。事实上,当我对其进行更多测试时,它确实会再次发生,并且它是否是浏览器的错误并不重要,因为使用 setTimeout 这种情况是完全不可能的。

于 2011-10-18T16:48:42.097 回答
2

控制台中的区别很明显:

在此处输入图像描述

于 2014-01-04T21:02:31.980 回答
2

只需添加已经说过的内容,但代码的 setTimeout 版本也将达到Maximum call stack size将阻止它运行的内容。由于递归函数没有停止的基本情况,因此您不能让它永远运行。

于 2014-05-26T15:43:34.317 回答
1

如果您将时间间隔设置setInterval得太短,它可能会在上一次调用该函数完成之前触发。我使用最近的浏览器(Firefox 78)遇到了这个问题。这导致垃圾收集无法足够快地释放内存并造成巨大的内存泄漏。UsingsetTimeout(function, 500);给了垃圾收集足够的时间来清理并保持内存随着时间的推移稳定。

Serg Hospodarets 在他的回答中提到了这个问题,我完全同意他的说法,但他没有包括内存泄漏/垃圾收集问题。我也经历了一些冻结,但内存使用量很快就达到了 4 GB,用于一些小任务,这对我来说真是太糟糕了。因此,我认为这个答案在我的情况下仍然对其他人有益。我会把它放在评论中,但缺乏这样做的声誉。我希望你不要介意。

于 2020-07-06T10:54:05.350 回答
0

选项 A选项 B看起来工作方式相同的原因主要是因为函数的位置和setInterval位置setTimeout

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

myTimeoutFunction();

这是一个递归函数,如果doStuff非常复杂,setTimeout必须跟踪所有对setTimoutplus currentdoStuff调用,这使得它变得越来越

function myTimeoutFunction()
{
    doStuff();
}

myTimeoutFunction();
setInterval(myTimeoutFunction, 1000);

另一方面,setIntervalonly 必须跟踪 lastsetInterval和 current doStuff,使其保持恒定速度。

那么你应该使用哪一个呢?

从上面,您应该可以得出结论,更好的是setInterval.

于 2021-03-11T17:06:32.213 回答
0

要考虑的重要一点是性能。定期运行函数的唯一方法setTimeout是使用目标函数递归调用它,当你检查它时,它似乎是异步工作的,当你看到调用堆栈时你会发现它一直在增长。事实上,这是明智的。由于Javascript不支持多线程,所以在子函数完成之前不可能完成父函数的调用,因此只要有递归调用,栈就会一直增长。同时,setInterval我们不需要递归调用目标函数,因为它有一个逻辑可以将其作为循环定期运行。因此,这使调用堆栈保持清洁。您可以使用浏览器中的开发人员工具查看调用堆栈,您会注意到其中的不同。

长时间使用小间隔时,差异会很明显。

于 2021-12-22T16:08:33.627 回答
-5

我认为SetIntervalSetTimeout不同。SetInterval根据设置的时间执行块 while,SetTimeout执行代码块一次。

在超时倒计时秒后尝试这组代码:

setInterval(function(e){
    alert('Ugbana Kelvin');
}, 2000);

然后尝试

setTimeout(function(e){
    alert('Ugbana Kelvin');
}, 2000);

您可以自己查看差异。

于 2013-04-17T02:15:31.997 回答