setTimeout还是setInterval?

时间:2009-04-08 13:11:01

标签: javascript setinterval

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

选项A:

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

myTimeoutFunction();

选项B:

function myTimeoutFunction()
{
    doStuff();
}

myTimeoutFunction();
setInterval(myTimeoutFunction, 1000);

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

20 个答案:

答案 0 :(得分:637)

  

有什么不同吗?

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

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

Timeout:

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

Interval:

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

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

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

表示一个间隔触发,无法立即执行其代码,而是取而代之。

因此,间隔试图'赶上'以便按时恢复。但是,它们并不排在一起:每个区间只能有一个执行挂起。 (如果他们都排队等候,浏览器会留下一个不断扩展的未完成执行列表!)

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

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

如果doStuff()函数的执行时间通常比为其设置的时间间隔长,那么浏览器将会尝试使用100%的CPU来为其提供服务,并且可能会降低响应速度。

  

你使用哪种?为什么?

Chained-Timeout为浏览器提供了保证的空闲时间; Interval尝试确保其运行的功能尽可能接近其预定时间执行,但代价是浏览器UI可用性。

我会考虑一次性动画的间隔,我希望尽可能平滑,而链式超时对正在进行的动画更加礼貌,这些动画会在页面加载时一直发生。对于要求较低的用途(例如每隔30秒触发一次微不足道的更新程序),您可以安全地使用它们。

就浏览器兼容性而言,setTimeout早于setInterval,但您今天将遇到的所有浏览器都支持这两种浏览器。多年来最后一个落后者是WinMo&​​lt; 6.5中的IE Mobile,但希望现在也落后于我们。

答案 1 :(得分:628)

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

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

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

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

答案 2 :(得分:85)

的setInterval()

setInterval()是一种基于时间间隔的代码执行方法,具有在达到间隔时重复运行指定脚本的本机能力。它应该嵌套到其回调函数中以使其循环,因为 默认循环 。除非你拨打clearInterval(),否则它将继续按间隔开火。

如果要循环播放动画代码或时钟节拍代码,请使用setInterval()

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

的setTimeout()

setTimeout()是一种基于时间的代码执行方法,当达到间隔时,该方法仅执行 一次 的脚本。它将再次重复,除非你通过将setTimeout()对象嵌套在它调用运行的函数内来设置循环脚本。如果适合循环,除非你拨打clearTimeout(),否则它将继续按间隔开火。

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

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

答案 3 :(得分:41)

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);

答案 4 :(得分:21)

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

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

myTimeoutFunction();

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

答案 5 :(得分:16)

差别在于他们的目的。

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

答案 6 :(得分:12)

当你在setInterval中运行一些函数时,它的工作时间超过timeout->浏览器将被卡住。

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

要防止出现这种情况,最好的方法是在setTimeout中运行 setTimeout来模拟setInterval
要纠正setTimeout调用之间的超时,可以使用self-correcting alternative to JavaScript's setInterval技术。

答案 7 :(得分:7)

我使用setTimeout。

显然差异是setTimeout调用方法一次,setInterval重复调用它。

以下是一篇解释差异的好文章:Tutorial: JavaScript timers with setTimeout and setInterval

答案 8 :(得分:5)

我对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
    });
}

答案 9 :(得分:3)

setInterval和setTimeout都返回一个可用于取消执行的计时器ID,即在触发超时之前。要取消,请调用clearInterval或clearTimeout,如下所示:

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

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

答案 10 :(得分:3)

您的代码将具有不同的执行间隔,并且在某些项目中,例如在线游戏,它是不可接受的。首先,你应该做什么,为了让你的代码以相同的间隔工作,你应该改变&#34; myTimeoutFunction&#34;对此:

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

此更改后,它将等于

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

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

    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毫秒,结果将是稳定的。

答案 11 :(得分:3)

稍微区别一点:setInterval确保代码以每个给定的间隔运行(即1000ms,或指定的数量),而setTimeout设置它等待“运行代码”的时间。并且由于运行代码需要额外的毫秒数,因此它会增加1000毫秒,因此,setTimeout会在不准确的时间(超过1000毫秒)再次运行。

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

答案 12 :(得分:2)

嗯,正如我刚刚学到的那样,setTimeout在某种情况下更好。我总是使用setInterval,我已经在后台运行了半个多小时。当我切换回那个标签时,幻灯片放映(使用代码的地方)变化非常快,而不是每5秒应该有。它实际上确实发生了,因为我测试它更多,是否是浏览器的错误并不重要,因为使用setTimeout这种情况是完全不可能的。

答案 13 :(得分:2)

您可以在运行以下javascript时自行验证bobince答案或查看此JSFiddle

<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);
});

答案 14 :(得分:1)

控制台的区别很明显:

enter image description here

答案 15 :(得分:1)

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

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

答案 16 :(得分:1)

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

答案 17 :(得分:0)

  

和setInterval(expression,   时间)

setTimeout()将仅在指定的持续时间之后执行一次表达式。

但是

setInterval()将在每个指定的持续时间之后在INFINITE-LOOP中执行表达式。

答案 18 :(得分:0)

选项 A选项 B 看起来效果相同的原因主要是因为 setIntervalsetTimeout功能。

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

myTimeoutFunction();

这是一个递归函数,如果 doStuff 非常复杂,setTimeout 必须跟踪 setTimout 的所有调用加上当前的 doStuff,其中使它变得

function myTimeoutFunction()
{
    doStuff();
}

myTimeoutFunction();
setInterval(myTimeoutFunction, 1000);

另一方面,setInterval 只需要跟踪最后一个 setInterval 和当前 doStuff,使其保持恒定速度.

那么你应该使用哪一个?

根据以上内容,您可能应该能够得出结论:更好的是 setInterval

答案 19 :(得分:-5)

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

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

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

然后尝试

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

你可以看到自己的差异。