传统的 JavaScript 动画是通过 setTimeout 或者 setInterval 实现的,但是定时器动画一直存在两个问题:
- 动画的循环间隔不好控制,设置长了动画显得不够平滑流畅,设置短了浏览器的重绘频率会达到瓶颈,推荐的最佳循环间隔是 17ms(大多数电脑的显示器刷新频率是 60Hz,1000ms/60)
- 定时器第二个参数只是指定了多久后将动画任务添加到浏览器的 UI 线程队列中,如果 UI 线程处于忙碌状态,那么动画不会立刻执行。
为了解决这些问题,H5 中加入了 requestAnimationFrame
和 requestIdleCallback
requestAnimationFrame
会把每一帧中的所有 DOM 操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率
在隐藏或不可见的元素中,requestAnimationFrame
将不会进行重绘或回流,这当然意味着更少的 CPU、GPU 和内存使用量
requestAnimationFrame
是浏览器专门为动画提供的 API,在运行时浏览器会自动优化方法的调用,并且如果页面不是激活状态下,动画会自动暂停,有效节省了 CPU 开销
# 性能对比
requestAnimationFrame
的回调会在每一帧确定运行,属于高优先级任务;而 requestIdleCallback
的回调则不一定,属于低优先级。
我们看到的网页都是浏览器一帧一帧绘制出来的,通常认为 FPS 为 60 是比较流畅的,而 FPS 为个位数的时候用户就会感受到明显的卡顿。
在每一帧里,浏览器都处理了一下的事情:
包含了用户的交互、js 的执行、以及 requestAnimationFrame 的调用,布局计算以及页面的重绘等工作。
假如某一帧里面要执行的任务不多,在不到 16ms(1000/60)的时间内就完成了上述任务的话,那么这一阵就会有一定的空闲时间,这段时间就恰好可以用来执行 requestIdleCallback
的回调: