跳到主要内容

定时器

setTimeout 为什么不能保证能够及时执行?

如果主线程被阻塞,就无法从消息队列中取出定时器任务。

setTimeout、setInterval 和 requestAnimationFrame 之间的区别

requestAnimationFrame与 setTimeout 和 setInterval 不同,requestAnimationFrame 不需要设置时间间隔, 大多数电脑显示器的刷新频率是 60Hz,大概相当于每秒钟重绘 60 次。大多数浏览器都 会对重绘操作加以限制,不超过显示器的重绘频率,因为即使超过那个频率用户体验 也不会有提升。因此,最平滑动画的最佳循环间隔是 1000ms/60,约等于 16.6ms。 RAF 采用的是系统时间间隔,不会因为前面的任务,不会影响 RAF,但是如果前面的任 务多的话, 会响应 setTimeout 和 setInterval 真正运行时的时间间隔。 特点: (1)requestAnimationFrame 会把每一帧中的所有 DOM 操作集中起来,在一次重绘或 回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率。 (2)在隐藏或不可见的元素中,requestAnimationFrame 将不会进行重绘或回流,这 当然就意味着更少的 CPU、GPU 和内存使用量 (3)requestAnimationFrame 是由浏览器专门为动画提供的 API,在运行时浏览器会 自动优化方法的调用,并且如果页面不是激活状态下的话,动画会自动暂停,有效节 省了 CPU 开销。

用 setTimeout 来实现 setInterval

每个 setTimeout 产生的任务会直接 push 到任务队列中;而 setInterval 在每次把任务 push 到任务队列前,都要进行一下判断(看上次的任务是否仍在队列中,如果有则不添加,没有则添加)。

setInterval的缺点,也就显而易见了:

使用setInterval时,某些间隔会被跳过(如果上一次执行代码没有执行,那么这次的执行代码将不会被放入队列,会被跳过) 可能多个定时器会连续执行(上一次代码在队列中等待还没有开始执行,然后定时器又添加第二次代码,第一次代码等待时间和执行时间刚好等于第二次代码执行)

var timeWorker = {}
var mySetInterval= function(fn, time) {
// 定义一个key,来标识此定时器
var key = Symbol();
// 定义一个递归函数,持续调用定时器
var execute = function(fn, time) {
timeWorker[key] = setTimeout(function(){
fn();
execute(fn, time);
}, time)
}
execute(fn, time);
// 返回key
return key;
}
var myClearInterval = function(key) {
if (key in timeWorker) {
clearTimeout(timeWorker[key]);
delete timeWorker[key];
}
}