requestAnimationFrame与setTimeout的定时器

之前参加网易游戏笔试时,第一道大题就是问的requestAnimationFrame这个API,同时让说明这个API与setTimeout的异同。当时看到的时候完全不知道requestAnimationFrame是什么,直接放弃。想着回来还是得吧这个知识盲点给补上。

setTimeout

setTimeout由浏览器的定时器模块来管理,当达到所设置的定时时间,就会将定时器绑定的事件(函数)加入到宏任务队列中。不同异步任务的执行顺序可参考事件循环任务执行顺序
通过在setTimeout绑定的函数中再绑定一个setTimeout来模拟setInterval定时器,如下代码所示,这样的好处是避免动画的抖动,保证下一次动画函数执行必须在当前动画执行结束后的再执行。

var i = 0;
var timer;
var foo = function() {
    console.log(i++);
    timer = setTimeout(foo, 1000)
}
foo();

但是,setTimeout并不能按照设置的定时准时触发,这点可以从js事件循环来解释。当设置了该定时器时,假设定时1000毫秒,

  • 首先,绑定函数交由定时器模块处理;
  • 然后,当到达1000毫秒时,定时器模块会将该绑定事件加入到任务队列中,注意,这个时候已经到了我们的预设时间了,但是实际上函数并没有被执行。
  • 最后,当任务队列中优先于该任务的函数执行完成后,才会执行该定时器绑定的函数。所以这里的实际执行的时间相比预设时间会更晚。

requestAnimationFrame

requestAnimationFrame和屏幕刷新是同步的,也就是说屏幕每刷新一次,requestAnimationFrame就触发一次。
由于requestAnimationFrame与浏览器刷新同步,因此不会像setTimeout那样积累时间上的误差。加入屏幕刷新率是60,则最小间隔时间是16.67ms。

var i = 0;
var timer;
var foo = function() {
    console.log(i++);
    timer = setTimeout(foo, 1000)
}
foo();

由于不同显示器的刷新率不同,因此如果要定时的话,时间也不相同。可以通过js来计算屏幕刷新率。

var refreshInterval;
(function(){
    var i = 0;
    var foo = function() {
        if (++i == 100) {
            refreshInterval = (new Date().getTime() - time1)/100;
            return;
        }
    }
    var time1 = new Date().getTime();
    foo();
}())
posted @ 2018-09-19 14:08  lyk_109  阅读(1151)  评论(0编辑  收藏  举报