与 setTimeout
、setInterval
不同,requestAnimationFrame
不需要设置时间间隔,这有什么好处呢?
计时器一直是 JavaScript 动画的核心技术,而编写动画循环的核心是要知道延迟时间多长合适。一方面循环间隔必须足够短,这样才能让不同的动画效果显得平滑顺畅,另一方面循环间隔要足够的长,这样才能保证浏览器有能力渲染产生的变化。
大多数电脑显示器的刷新频率是60Hz,大概相当于每秒重绘60次。大多数浏览器都会对重绘操作加以限制,不会超出显示器的重绘频率。
而 setTimeout
和 setInterval
的缺点是他们都不够精确。它们内在的运行机制决定了时间间隔参数实际上只是指定了把动画代码添加到浏览器 UI 线程队列中等待执行的时间,如果队列中已经加入了其他任务,那么动画的执行要等前面的任务结束之后才会执行。
requestAnimationFrame
采用的是系统时间间隔,保证了最佳绘制效率。不会因间隔时间过短,造成过度绘制,增加开销;也不会因时间间隔太长,造成动画卡顿。它能够让各种网页动画有一个统一的刷新机制,从而节省系统资源,提高系统性能,改善视觉效果。
特点
requestAnimationFrame
会把每一帧中的所有 DOM 操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率。- 在隐藏或不可见的元素中,
requsetAnimationFrame
将不会进行重绘或回流,这就意味着更少的 CPU、GPU 和内存使用量。 requestAnimationFrame
是浏览器专门提供的 api,在运行时浏览器会自动优化方法的调用,并且页面不是激活状态下,动画会暂停执行,有效节省 CPU 开销。
使用
requestAnimationFrame
使用一个回调函数作为参数,这个回调函数会在浏览器重绘之前调用。他返回一个整数,标识定时器的编号,这个值可以传递给 cancelAnimationFrame
用于取消这个函数的执行。
const requestId = requestAnimationFrame(callback);
//控制台输出1和0
var timer = requestAnimationFrame(function(){
console.log(0);
});
console.log(timer);//1
cancelAnimationFrame方法用于取消定时器
//控制台什么都不输出
var timer = requestAnimationFrame(function(){
console.log(0);
});
cancelAnimationFrame(timer);
也可以直接使用返回值进行取消
var timer = requestAnimationFrame(function(){
console.log(0);
});
cancelAnimationFrame(1);
兼容
IE9-浏览器不兼容该方法,可以使用 setTimeout 来兼容
if(!window.requestAnimationFrame){
let lastTime = 0;
window.requestAnimationFrame = function(callback){
const currTime = new Date().getTime();
const timeToCall = Math.max(0, 16.7-(currTime - lastTime));
const id = window.setTimeout(function(){
callback(currTime + timeToCall);
},timeToCall);
lastTime = currTime + timeToCall;
return id;
}
}
if(!window.cancelAnimationFrame){
window.cancelAnimationFrame = function(id){
clearTimeout(id);
}
}