setTimeout或setInterval?

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

选项A:

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

选项B:

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

使用setTimeout和setInterval有什么区别吗?

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

虽然人们可能会认为setInterval每1000毫秒执行一次,但重要的是要注意, setInterval也会延迟,因为JavaScript不是multithreading语言,这意味着 – 如果脚本的其他部分正在运行 – 间隔将不得不等待完成。

在这个小提琴中 ,你可以清楚地看到超时将落后,而几乎所有的时间差不多在1次/秒(剧本正在尝试)。 如果将顶端的速度variables改为20(意思是每秒运行50次),那么间隔永远不会达到平均每秒50次迭代。

延迟几乎总是可以忽略的,但是如果你编写了一些非常精确的东西,你应该去做一个自我调整的定时器 (本质上是一个基于超时的定时器,不断地调整自己以适应它所创build的延迟)

有什么区别吗?

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

如果您的doStuff()函数需要一段时间才能执行,您将注意到不同之处。 例如,如果我们表示调用setTimeout / setInterval . ,超时/间隔与*和JavaScript代码执行与[-----]的发射,时间线如下所示:

 Timeout: . * . * . * . * . [--] [--] [--] [--] Interval: . * * * * * * [--] [--] [--] [--] [--] [--] 

接下来的复杂情况是,如果一段时间间隔触发,而JavaScript已经忙于做某事(例如处理以前的时间间隔)。 在这种情况下,间隔会被记住,并且只要前一个处理程序结束并将控制权返回给浏览器,就会发生。 所以例如对于有时短([ – ]),有时长([—–])的doStuff()进程:

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

•表示间隔射击,不能马上执行它的代码,而是取而代之。

所以间隔时间试图“赶上”按时返回。 但是,它们并不排队,每个区间只能有一个挂起执行。 (如果他们全部排队,浏览器将留下一个不断扩大的执行清单!)

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

x代表一个无法执行或不能执行的间隔触发,所以被丢弃。

如果您的doStuff()函数习惯性地花费比设置的时间间隔更长的时间,浏览器将尝试使用100%的CPU尝试提供服务,并且响应速度会变慢。

你使用哪个,为什么?

链接超时为浏览器提供了保证的空闲时间。 Interval尝试确保其运行的function尽可能接近其预定的时间,但牺牲了浏览器的UI可用性。

我会考虑一次性animation的间隔,我希望尽可能平滑,而链接超时更有礼貌,因为正在进行的animation会在页面加载的过程中一直发生。 对于要求不高的用途(例如每30秒发射一次微小的更新),您可以安全地使用。

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

的setInterval()

setInterval()是一个基于时间间隔的代码执行方法,具有在到达间隔时重复运行指定脚本的本地function。 它不应该被脚本作者嵌套到它的callback函数中,因为它默认循环的 。 除非调用clearInterval()否则它将继续在间隔内触发。

如果你想循环代码animation或时钟滴答,然后使用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() 。 这是因为它只在达到指定的时间间隔时执行一次。

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

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

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

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

差别在于他们的目的。

 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

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

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

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

我使用setTimeout。

显然不同的是setTimeout调用方法一次,setInterval重复调用它。

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

我已经做了setInterval(func, milisec)简单testing,因为我很好奇当函数时间消耗大于间隔持续时间时会发生什么情况。

setInterval 通常会在上一次迭代开始之后计划下一次迭代, 除非函数仍在进行中 。 如果是这样, setInterval将等待,直到函数结束。 一旦发生,函数立即再次被触发 – 没有按照时间表等待下一次迭代(因为它将在没有超过函数的时间的情况下)。 并行迭代运行也不存在。

我已经在Chrome v23上testing过了。 我希望这是所有现代浏览器的确定性实现。

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

这篇文章说,如果可能的话,你应该避免使用setInterval,特别是因为你可以通过setTimeout复制它的行为,并获得一些额外的好处。

setInterval和setTimeout都会返回一个可以用来取消执行的定时器ID,也就是在超时被触发之前。 要取消你调用clearInterval或clearTimeout像这样:

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

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

那么,setTimeout在一种情况下更好,就像我刚刚学到的那样。 我总是使用setInterval,我已经在后台运行了半个多小时。 当我切换回该选项卡时,幻灯片(使用的代码)变化非常迅速,而不是每5秒它应该有。 它确实再次发生,因为我testing它更多,是否浏览器的错误并不重要,因为setTimeout这种情况是完全不可能的。

在控制台中的区别很明显:

在这里输入图像描述

只要添加到已经说过的,但setTimeout版本的代码也将达到Maximum call stack size ,将停止运作。 因为recursion函数没有基本的例子,所以你不能永远运行它

当你运行下面的javascript或者检查这个JSFiddle时,你可以自己validationbobince的回答

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

你的代码将有不同的执行间隔,在一些项目,如在线游戏,这是不可接受的。 首先,你应该做什么,使你的代码工作在相同的时间,你应该改变“myTimeoutFunction”为:

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

在这个变化之后,它将等于

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

但是,你仍然不会有稳定的结果,因为JS是单线程的。 现在,如果JS线程忙于某些事情,它将无法执行你的callback函数,执行将推迟2-3毫秒。 你是否每秒执行60次,每次你有1-3秒的延迟时间,都是绝对不能接受的(一分钟后会有7200毫秒左右的延迟),我可以build议使用类似这样的东西:

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

要看看它有点不同:setInterval确保代码是在每个给定的时间间隔(即1000毫秒,或指定多less)运行,而setTimeout设置它等待的时间,直到它运行的代码。 而且由于运行代码需要额外的毫秒数,所以它加起来高达1000毫秒,因此,setTimeout在不精确的时间(超过1000毫秒)再次运行。

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

这可能会更好地取代第一个function

选项A'

 function myTimeoutFunction() { setTimeout(myTimeoutFunction, 1000);// At first doStuff(); } myTimeoutFunction(); 

不是吗?

我认为setTimeout版本可能实际上泄漏内存。 你recursion地调用一个不返回的函数。 所以每个电话都有一个返回地址,但是没有popup。 此外,对于tick函数中定义的每个variables,都有范围分配,因为范围从不退出,所以没有机会获得释放。

 var i = 0; //The parameter leaks stack memory function tickFunction(param) { //The following array leaks heap memory var heapLeakArray = ["sdsadsasad", "dsadsadsasa", "dsadsadsa"]; //The following call leaks stack memory setTimeout(function(){tickFunction(++param);}, 10); } 

所以为了调度目的,我build议你使用setInterval方法,而setTimeout方法更适合延迟执行和asynchronous工作。

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

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

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

然后尝试

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

你可以看到自己的差异。