初识 requestAnimationFrame

事情的起因是这样的,前段时间面试的时候面试官问我会canvas不,作为一名未来的前端猿,我只有过一点了解,后来居然收到了offer,当然在闲暇之余是要学习一下canvas,并且在学习过程中首次接触到了本文的主角requestAnimationFrame

web中实现动画

老实说,如果有人问我如何在web开发中实现动画,我第一时间想到的就是使用定时器setTimeout()或者setTimeInterval()来实现。其实实现的方式远远不止这一种,在CSS3的时代,我们实现动画有了更多的选择,比如使用关键帧动画,使用transition,我们也可以在canvas上绘图来实现动画;当然,还有requestAnimationFrame

使用setTimeout()/setInterval()实现的方式很简单,我前面有一篇文章就简要介绍了JS中的定时器。使用这种方式实现动画其实是有其性能瓶颈的,例如:

1
2
3
4
function animation(){
// do something
setTimeout(animation, 1000/60)
}

上面我们以60帧/秒的速度执行动画,但是如果浏览器不是60帧/秒,就会掉帧;并且由于JS单线程的特点,所有不能保证每一次执行回调都是1000/60毫秒;还有,当窗口处于非激活状态的时候,它同样可能会执行。

其实很好理解,作为定时器,setTimeout/setInterval并不是专门做动画的,存在各种各样的问题也是很好接受的,但是当我们认识到这种实现动画的方式的各种缺点时,我们也许会考虑另一种动画的实现方式,而requestAnimationFrame是一种更好的方案。

初识 requestAnimationFrame

当我们执行window.requestAnimationFrame(callback)的时候,浏览器会在下次重绘的时候执行回调函数,它会告诉浏览器马上就要执行动画了,而callback则是用于更新动画。

requestAnimationFrame使用起来很简单,通过递归不断来执行回调来更新画面从而让画面动起来,我们甚至不需为其指定动画执行的时间和帧率。其优点是:1)从名字上就可以看出这是一个专门用于实现动画的API,优化是自然少不了的;2)其如果处于非激活状态,会自动暂停执行,有效节省了CPU资源。

小实例

我们在做动画的时候,有时希望背景移动起来,结合目前正在学习的canvas,我们可以很轻易的做到这点.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let j = 0;
let image = document.querySelectorAll('img')[0];
function moveBackground(){
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.translate(10, 0);
ctx.drawImage(image, 0, 0);
j++;
if(j < 20){
requestAnimationFrame(moveBackground);
}
}
let moveBtn = document.getElementById('move');
moveBtn.onclick = function(e){
e.preventDefault();
requestAnimationFrame(moveBackground);
}

上面我们点击button的时候,开始执行动画,通过不断的坐标变换和清除重绘,达到背景图片向右移的效果。

最后,请注意,不是所有浏览器都支持该方法,所以你可能需要一个polyfill,关于如何实现这个polyfill,网络上的资源比较多了,这里就不在赘述。

分享到 评论