使用setTimeout()和setInterval()创建的定时器可以很多的功能,比如在一定时间后执行代码,实现秒级或者毫秒级的倒计时,等等。可是我们需要知道的是Javascript是 单线程运行的,每次都会从执行队列中取出将要执行的代码开始执行;而定时器仅仅是将我们将要运行的代码加入到执行队列中,至于什么时候执行,那就得看这个执行队列的前面有没有其他执行的代码了。
1. 高级定时器 #
定时器对队列的工作方式是:当我们设置的时间过去后,将代码插入到执行队列注意,给队列添加代码并不意味着对它立即执行,而只能表示它会尽快执行。设定150ms后执行的定时器不代表到了150ms代码就立刻执行。它表示代码会在150ms后被加入到队列中。如果在这个时间点上队列中没有其他东西,那么这段代码就会被执行,表面看上去好像代码就在精确指定的时间点上执行了。其他情况下,代码可能明显地等待更长时间才执行。
队列中所有的代码都要等到Javascript
进程空闲之后才能执行,而不管它们是如何添加到队列中的。
hello world
实际上,firefox中定时器的实现还能让你确定定时器过了多久才执行,这需要传递一个实际执行的时间与指定的间隔的差值。如:
// 仅firefox中
setTimeout(function(diff){
if(diff>0){
// 晚调用
}else if(diff<0){
// 早调用
}else{
// 调用及时
}
})
2. 重复定时器setInterval() #
使用setInterval()创建的定时器确保了定时器代码规则地插入队列中。这个方式的问题在于,定时器代码可能在代码再次被添加到队列之前还没有执行完毕,结果导致定时器代码连续运行好几次,而之间没有任何停顿。幸好,Javascript引擎规避了这个问题,当使用setInterval()时,仅当没有该定时器的任何其他代码实例时,才将定时器代码添加到队列中。这确保了定时器代码加入到队列中的最小时间间隔为指定间隔。
不过即使是这样的规则,也会出现两个问题:1)某些间隔会被跳过;2)多个定时器的代码执行之间的间隔可能回避预期的小。
比如定时器里添加的代码运行的时间很长,导致有些间隔不能被添加到执行队列里,不能执行。