setInterval的问题及解决方案

问题

  1. setInterval的定时器代码可能在下一次添加到队列之前,还没有执行完成。导致定时器代码连续执行,设置的间隔就没有意义。

    javascript引擎的方案是,仅当队列中没有定时器代码实例的时候,才增加新的代码实例,这样就保证了定时器代码实例加入到队列中时,最小的时间间隔为指定间隔

  2. javascript引擎的方案虽然解决了定时器代码实例加入队列的问题,但是又出现了新的问题,如果回调执行的时间比设定的时间间隔长,某些预定的执行会被跳过,另外因为执行时间的不确定性,会导致多次回调执行之间的间隔比预期的小

解决办法

要解决这些问题,可以使用链式setTimeout来替代setInterval

1
2
3
4
setTimeout(function fn(){
// 执行业务代码,执行完成后,设定一个任务
setTimeout(fn,interval);
},interval)

这样就可以保证在当前定时器代码没有执行结束前,不会向队列中添加新的定时器代码实例,确保不会出现循环的定时器事件出现缺失; 而且可以确保在第一次定时器代码执行前,至少要等待指定的时间,避免了连续执行。

注意

在定时器任务中,var timer=setTimeout(function(){})执行后,清除定时任务clearTimeout(timer)timer=null是有区别的,timer只是一个定时任务的一个标示量,设置为null仅仅是改变了timer变量的值,对设定的任务没有影响,只有通过clearTimeout(timer)才是真的清除定时任务

扩展

HTML5标准规定,setTimeout的最短时间间隔是4毫秒;setInterval的最短间隔时间是10毫秒,也就是说,小于10毫秒的时间间隔会被调整到10毫秒

大多数电脑显示器的刷新频率是60HZ,大概相当于每秒钟重绘60次。因此,最平滑的动画效的最佳循环间隔是1000ms/60,约等于16.6ms

为了节电,对于那些不处于当前窗口的页面,浏览器会将时间间隔扩大到1000毫秒。另外,如果笔记本电脑处于电池供电状态,Chrome和IE10+浏览器,会将时间间隔切换到系统定时器,大约是16.6毫秒