requestAnimationFrame 是什么?
它是一个浏览器提供的 API,用于在浏览器重绘之前调用指定的回调函数。它可以让浏览器在重绘之前更新动画/视觉效果,从而实现平滑的动画效果。
使用场景:requestAnimationFrame 经常用来构建平滑的动画效果和视觉效果。比如页面滚动,CSS3 过渡和动画,canvas 动画等。
原理:requestAnimationFrame 将回调函数加入浏览器的回调队列中,在下一次重绘之前调用。一般来说,屏幕刷新频率是 60Hz,也就是说每秒重新绘制 60 次。requestAnimationFrame 试图将重绘与此刷新频率同步,从而实现平滑的动画效果。
与 setTimeout/setInterval 的比较:
requestAnimationFrame 与 setTimeout/setInterval 都可以实现定时执行代码的功能,但 requestAnimationFrame 有更好的性能表现。这是因为:
- requestAnimationFrame 与屏幕刷新同步,只在需要重绘的时候执行回调,而 setTimeout 是按照固定时间间隔执行。
- requestAnimationFrame 会把多个回调集中在一起执行,减少重绘次数,而 setTimeout 会每个时间间隔就重绘一次。
- requestAnimationFrame 可以保证平滑的动画效果,而 setTimeout 可能由于间隔时间过长产生卡顿感。
所以,在不需要严格的时间间隔要求和需要平滑动画的场景下,requestAnimationFrame 是更好的选择。
不同浏览器的实现差异:
不同浏览器的刷新频率可能不同,实现方式也可能略有差异,这可能会导致动画效果在不同浏览器中有细微的差别。
在我的电脑上,屏幕的刷新率是 60Hz,它每一次的刷新频率大概是 16.666ms。
优点:
- 与屏幕刷新频率同步,实现平滑的动画效果;
- 节省 CPU、GPU 和电量;
- 避免布局抖动等视觉差异。
缺点:
- 回调函数的调用频率受屏幕刷新频率的限制,在低刷新频率下会感觉到卡顿;
- 若连续调用 requestAnimationFrame,可能会导致过高的 CPU 占用,应避免请求动画帧的频率超过屏幕刷新频率;
- 部分低端机型的刷新频率较低,动画效果可能不太平滑。
使用示例:
1 | function animate() { |
可以使用 cancelAnimationFrame 取消一个 requestAnimationFrame 的回调函数。例如:
1 | let rafId; |