requestAnimationFrame 是什么
语法:requestAnimationFrame(callback)
requestAnimationFrame 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。
⚠requestAnimationFrame()是一次性的
- 也就是说,若你想在浏览器下次重绘之前继续更新下一帧动画,那么回调函数自身必须再次调用 requestAnimationFrame()
requestAnimationFrame 解决了什么问题?
- 它本质上解决了定时器时间间隔不稳定的问题,可以将它看作是 setInterval 和 setTimeout 更好的解决方案
- 因为显示屏的刷新频率是 60HZ,也就是每秒刷新 60 次。那么 1000ms 下,刷新 60 次所需时间为 1000/60≈16.67ms,这就是浏览器所显示的最大的刷新频率了。
- 如果刷新频率> 16.67ms,并不会提升用户体验;反之,我们需要找到靠近 16.67ms 的时间,也就是 16 或者 17,在这个时间下的动画就会显得比较平滑了。
假如将 setInterval 或 setTimeout 的时间间隔设置为 16.67,会怎么样?
众所周知,setInterval 和 setTimeout 都属于异步 API,并且也属于宏任务。那么它们就需要等待同步任务以及微任务完成以后,才会执行传入的回调函数。这就造成了一个问题:无法精准地将时间定位到 16.67,即使换成 16 或者 17,也无法精确定位。
那么,requestAnimationFrame 的出现就解决了以上问题。
首先,需要明确的一点是:requestAnimationFrame 不是由 JavaScript 控制的,而是由系统的时间间隔来控制。这样带来的好处就是,不会因为 JavaScript 代码,导致当前任务时间间隔不准的问题。
所以,requestAnimationFrame 的解决方式就是采用系统的时间间隔。
从而,requestAnimationFrame 与 setInterval、setTimeout 的区别就是:
- requestAnimationFrame 的时间间隔是由系统来控制,而非 setInterval、setTimeout 的时间间隔由我们来控制
- 因此,这就可以解释:在 requestAnimationFrame 的语法使用上,为什么不用指定时间间隔了
使用方法
同样地,requestAnimationFrame 也可以像 setInterval、setTimeout 一样访问到当前的 timer
与 clearTimeout 和 clearInterval 一样,requestAnimationFrame 也有着自己的清除定时器的 API(cancelAnimationFrame)。
但值得注意的是:window.cancelAnimationFrame 是一个 Experimental 功能,即是一个实验中的功能。那么意味着此功能某些浏览器尚在开发中,请参考浏览器兼容性表格以得到在不同浏览器中适合使用的前缀。
兼容性处理
由于 requestAnimationFrame 是 HTML5 新增的一个 API,那么必然存在着兼容性的问题
测试例子
以下导航条的测试例子
效果视频
可以明显的看出,requestAnimationFrame 更快。当然,也不是非得用 requestAnimationFrame,只是在做相对复杂的动画效果时,它能带来更好的用户体验。