setTimeout还是setInterval?

Dam*_*isa 738 javascript setinterval

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

选项A:

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

myTimeoutFunction();
Run Code Online (Sandbox Code Playgroud)

选项B:

function myTimeoutFunction()
{
    doStuff();
}

myTimeoutFunction();
setInterval(myTimeoutFunction, 1000);
Run Code Online (Sandbox Code Playgroud)

使用setTimeoutsetInterval有什么区别吗?

Dav*_*unt 648

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

Altough有人可能会认为setInterval将执行完全相同每1000毫秒,一定要注意这一点很重要setInterval也将推迟,因为JavaScript是不是多线程的语言,这意味着-如果有脚本运行的其它部分-区间将有等待那个完成.

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

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

  • 从技术上讲,代码不会每1000毫秒执行*,因为它取决于计时器的分辨率以及其他代码是否已在执行.你的观点仍然存在. (61认同)
  • 理论上,是的.在实践中,没有,因为Javascript不支持多线程.如果您的代码耗时超过1000毫秒,它将冻结浏览器. (14认同)
  • setInterval在两个方面有所不同,1.setInterval不是递归的,setInterval会在告诉时间后第一次调用你的函数,而setTimeout第一次被调用没有任何延迟,之后它会在告知时间后再次调用.首次执行后,他们的工作几乎相同. (10认同)
  • 不同之处在于setTimeout不会重复.它允许您在设定的时间后运行脚本,但只能运行一次.另一方面,setInterval将重复该脚本,直到使用clearTimeout()停止它. (5认同)
  • 安迪有类似的建议.假设,这是否意味着如果该方法执行时间超过1000毫秒,您可以同时运行多个? (4认同)
  • 请注意,如果您未能及时为其服务,则间隔仍可能会延迟或丢失(请参阅下文). (2认同)

bob*_*nce 642

有什么区别吗?

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

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

Timeout:

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

Interval:

.    *    *    *    *    *    *
     [--] [--] [--] [--] [--] [--]
Run Code Online (Sandbox Code Playgroud)

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

.    *    *    •    *    •    *    *
     [-]  [-----][-][-----][-][-]  [-]
Run Code Online (Sandbox Code Playgroud)

•表示无法立即执行其代码的间隔触发,而是取而代之.

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

.    *    •    •    x    •    •    x
     [------][------][------][------]
Run Code Online (Sandbox Code Playgroud)

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

如果你的doStuff()函数习惯性地执行的时间比为它设置的时间间隔要长,那么浏览器会吃100%的CPU来尝试为它提供服务,并且可能会降低响应速度.

你用哪个?为什么?

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

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

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

  • 在匿名函数上执行链式超时的好方法:setTimeout(function(){setTimeout(arguments.callee,10)},10) (2认同)

Har*_*ris 88

的setInterval()

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

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

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

的setTimeout()

setTimeout()是,将执行一个脚本仅基于时间的代码执行方法一次到达的时间间隔时.它不会再次重复,除非你通过将setTimeout()对象嵌套在它调用运行的函数内来使其循环脚本.如果适合循环,除非你打电话,它将继续按间隔射击clearTimeout().

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

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

  • 很好的解释,但请注意OP了解OP提供的示例中的基本差异.特别要注意的是,在OP的`setTimeout()`示例中,`setTimeout()`被称为**递归**,而`setInterval()`则不是. (6认同)

Kam*_*oij 43

setInterval可以更容易地取消将来执行代码.如果使用setTimeout,则必须跟踪计时器ID,以备日后取消时使用.

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

myTimeoutFunction();

// later on...
clearTimeout(timerId);
Run Code Online (Sandbox Code Playgroud)

function myTimeoutFunction()
{
    doStuff();
}

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

// later on...
clearInterval(timerId);
Run Code Online (Sandbox Code Playgroud)

  • 在setInterval的情况下,我不知道你是如何不跟踪计时器id的.它刚刚退出了这个功能. (35认同)
  • Kekoa,好点.但是你必须只保存一次间隔id.超时ID可能随每次调用而变化,因此您必须_keep跟踪这些更改.想要清除超时的代码必须以某种方式访问​​此变量的当前值.另外,在运行`doStuff`时无法清除超时,因为id无效.但是,没有必要保存超时ID.相反,你可以停止调用`setTimeout`. (7认同)
  • 根据我的经验,即使在使用setTimeout时,大多数时候您也希望能够取消.99%的时间要在*下一次调用之前取消*,而不是*在*下一次调用完成之后. (4认同)

Guf*_*ffa 22

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

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

myTimeoutFunction();
Run Code Online (Sandbox Code Playgroud)

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


kma*_*o23 17

差别在于他们的目的.

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

setTimeout()
   -> executes a function, once, after waiting a specified number of milliseconds
Run Code Online (Sandbox Code Playgroud)

就这么简单

更详细的详细信息,请访问http://javascript.info/tutorial/settimeout-setinterval

  • 简明扼要的解释,但请注意OP了解OP提供的示例中的基本差异.特别要注意的是,在OP的`setTimeout()`示例中,`setTimeout()`被称为**递归**,而`setInterval()`则不是. (7认同)

Ser*_*ets 13

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

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

要防止出现这种情况,最好的方法是在setTimeout中运行setTimeout来模拟setInterval.
要纠正setTimeout调用之间的超时,您可以使用JavaScript的setInterval技术的自我更正替代方法.

  • 我不知道为什么没有人在这个答案中发现任何价值! (2认同)

Bra*_*vax 8

我用setTimeout.

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

这是一篇很好的解释差异的文章:教程:带有setTimeout和setInterval的JavaScript定时器

  • 是的,我有所不同,但我提供的两段代码应该做同样的事情...... (2认同)

Hel*_*lgi 6

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

var timeoutId = setTimeout(someFunction, 1000);
clearTimeout(timeoutId);
var intervalId = setInterval(someFunction, 1000),
clearInterval(intervalId);
Run Code Online (Sandbox Code Playgroud)

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


jwa*_*zko 6

我做了简单的测试setInterval(func, milisec),因为我很好奇当功能时间消耗大于间隔持续时间时会发生什么.

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

我在Chrome v23上测试了这个.我希望它是所有现代浏览器的确定性实现.

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

控制台输出:

fired: 1000    + ~2500 ajax call -.
fired: 3522    <------------------'
fired: 6032
fired: 8540
fired: 11048
Run Code Online (Sandbox Code Playgroud)

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

function wait() {
    $.ajax({
        url: "...",
        async: false
    });
}
Run Code Online (Sandbox Code Playgroud)


deg*_*egr 6

您的代码将具有不同的执行间隔,在某些项目(例如在线游戏)中,这是不可接受的。首先,您应该怎么做才能使代码以相同的间隔工作,您应该将“ myTimeoutFunction”更改为:

function myTimeoutFunction()
{
    setTimeout(myTimeoutFunction, 1000);
    doStuff();
}
myTimeoutFunction()
Run Code Online (Sandbox Code Playgroud)

更改之后,它等于

function myTimeoutFunction()
{
    doStuff();
}
myTimeoutFunction();
setInterval(myTimeoutFunction, 1000);
Run Code Online (Sandbox Code Playgroud)

但是,由于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();
Run Code Online (Sandbox Code Playgroud)

此代码将保证稳定的执行期限。甚至线程都将繁忙,并且您的代码将在1005毫秒后执行,下一次它将有995毫秒的超时,结果将保持稳定。


Cat*_*rta 5

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

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