简介
以往常常使用 setTimeout 以及 setInterval 方法来制作 JavaScript 动画,但是这种方式制作的动画经常会由于计时器的特性而带来一些问题。简单地说一下,计时器动画有以下几个问题。
- 间隔时间不精确,可能被阻塞。计时器的间隔指的是将回调函数推入任务队列的间隔时间,任务队列中的任务只有在主线程任务执行完毕后才会被执行。
- 计时器动画的间隔时间如果设定过短就会出现过度渲染占用大量资源,如果设定过长就会影响动画的流畅度。只能够估计合适的时间间隔。
- 多数浏览器对于计时器动画没有优化。
使用 requestAnimationFrame 方法来定义动画就不会出现以上这些问题。
- requestAnimationFrame 动画的帧数是由系统根据当前页面是否可见,CPU 的占用情况等等来决定的,可以最大化地利用系统性能。
- 浏览器对 requestAnimationFrame 动画进行了优化。
使用
requestAnimationFrame() 方法接收一个参数,即要执行的回调函数。这个回调函数会默认地传入一个参数,即从打开页面到回调函数被触发时的时间长度,单位为毫秒,精确度为10微秒。这个方法返回一个唯一的 handle 值,handle值 作为这个回调函数唯一的标识符,可以通过将这个标识符传给 cancleAnimationFrame() 方法来取消这个回调函数。
原理
requestAnimationFrame() 方法接受一个回调函数,同时随机生成一个唯一的 handle 值作为标识符。回调函数和 handle 值共同组成一个元组 <handle, callback>,然后将这个元组推入动画帧请求回调函数队列中。
当页面可见时,如果动画帧请求回调函数队列中有元组,那么浏览器就会清空队列并且执行这些回调函数。
另外,每一个元组有一个 canceled 标识符,如果为 false,那么这个回调函数就不会在清空队列后被执行。cancleAnimationFrame() 方法的原理就是将这个标识符设置为 false。
示例
var startTime;
function sayHi(time){
if(!startTime){
startTime = time;
}
time -= startTime;
console.log("Hi");
if (time <= 2000) {
requestAnimationFrame(sayHi);
}
}
requestAnimationFrame(sayHi);