Javascript深入浅出之定时器

前一篇文章聊单线程的时候,简要的提到了定时器的执行情况。这里我们将对其进行更多的探讨。

setTimeout 和 setInterval 的区别

可能看到这个小标题大家第一时间想到的都是,setTimeout 只执行一次,而 setInterval 则是重复执行。Oh,no!我们今天当然不能讲的这么浅,我们需要谈到的是 迭代setTimeout 和 setInterval 的区别。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function foo1() {
// statement1
setTimeout(function bar1() {
// statement2
}, 100);
}
function foo2() {
setTimeout(function bar2() {
// statement2
}, 100);
// statement1
}

我们思考一下,上面这段代码,同样的两个 setTimeoutfoo1foo2 中执行情况会一样吗?如果不一样,为什么?

答案是——不一样!很简单,setTimeout 执行时机就不一样, bar1 会早于 bar2 进入任务队列。现在我们要来细细地看一下它们的执行时间相差几何。

假设任务队列为空,这是我们的理想环境,就像物理课上我们假设小木块与冰面的摩擦力为 0 。

如果继续假设 statement1 的执行时间为 50ms ,foo1 中,会于 50ms 时启动定时器,并于 150ms 时将 bar1 插入任务队列并立即被读取执行, foo2 会于 0ms 处启动定时器,但是需要 100ms 处才能被插入任务队列,此时 statement1 已经执行完了,所以可以立即读取。他们相差 50ms 。

如果假设 statement1 的执行时间为 200ms ,foo1 中,会于 200ms 时启动定时器,并于 300ms 时将 bar1 插入任务队列并立即被读取执行, foo2 会于 0ms 处启动定时器,但是需要 100ms 处才能被插入任务队列。此时 statement1 还没有执行完毕,需要继续等到,到 200ms 时可以读取任务队列中的 bar2。他们相差 100ms 。

所以我们可以得出结论,bar1bar2 的执行时间相差的是 statement1执行时间 和 定时器设定时间 两者中较小的那个。

而我们使用迭代定时器的时候大多是像 foo1 那样使用,因为在进行下一次的 setTimeout 之前,我们会有一些必要的操作以及判断。而这也就代表着,两次 setTimeout 之间的间隔是 >= 指定时间的。

setInterval 则不然,它不管你的回调函数里面都需要怎样的操作,它会很准时的每隔指定的时间就去向任务队列中添加任务的。

setInterval 的缺点

setInterval 的定时的准确性,看似完美,实则不然。我们回顾一下上一篇文章中展示的例子,首先,如果当前队列中有相同的 setInterval 实例,则无法继续添加,也就是说,可能会造成 setInterval 的执行次数的遗漏。再者,如果 setinterval 之前被阻塞了,那么则会造成接下来的两次 setinterval 的执行间隔时间小于指定时间。

因为这两个特性,所以很多人都会建议说少用 setInterval ,改用迭代 setTimeout 。但是诚如上面我们看到的, setTimeout 也不如我们所想象的那么完美,那么我们有没有什么更好的解决方法呢?

requestAnimationFrame

大多显示器的显示频率是 60HZ ,也就是每次刷新间隔 16.7ms ,如果我们使用 setTimeout/setInterval 的间隔小于 16.7ms ,这就要造成显示器重绘的堵塞压力,每隔一段时间就会丢失掉一次定时器的执行绘制。这也就是为何 setTimeout 的定时器推荐最小使用 16.7ms 。

requestAnimationFrame 即时顺应时代的浪潮而出生的,它和上面那两位最大的区别是,它的执行间隔时间是不由我们来控制的,只跟着显示器的绘制间隔走,显示器多久绘制一次,它就多久执行一次。

当然,它的妙用可不仅仅只是这些,如果同时有几个 requestAnimationFrame ,页面重绘之前,会通知浏览器把需要执行的几个函数执行一下(它们可能在不同的 requestAnimationFrame 中),执行好了之后一并绘制,而在 setTimeout 中则不行,大家排队,挨个执行然后重绘。

而且如果页面最小化了,或者被切换到其他 Tab 了, requestAnimationFrame 会暂停执行,优化资源的利用。

但是它不支持 IE9 及之前的版本哦~

最后我们就放个实例吧。


定时器东西不多,这就讲完了,下一篇文章可以看一下定时器的一些应用~

热评文章