用requestAnimationFrame写的动画为什么会偶尔卡顿?
我在用JS写一个简单的位移动画,用requestAnimationFrame控制帧率,但发现动画偶尔会出现卡顿。代码看起来没问题,尝试过把时间间隔改成16ms还是没改善,这是为什么啊?
这是我的代码:
let pos = 0;
function animate(time) {
pos = time / 50;
elem.style.left = pos + 'px';
// 这里是不是哪里写错了?
requestAnimationFrame(animate(time + 10));
}
requestAnimationFrame(animate);
测试时发现当快速切换标签页再回来,卡顿更严重。明明用了浏览器内置的帧动画API,为什么还会这样?是不是时间计算有问题?
requestAnimationFrame的回调函数是由浏览器自动传入时间戳的,你不能手动传参animate(time + 10)这样调用,这会导致递归调用栈溢出或者行为异常。正确的写法应该是直接传函数引用。另外,动画卡顿的原因主要和浏览器的渲染机制有关。当你切换标签页时,浏览器会对非活动标签页中的
requestAnimationFrame进行降频处理,可能从 60fps 降到个位数 fps,等你切回来时会有一段时间的追赶过程,这就导致了卡顿现象。通用的做法是通过时间戳来计算真实的时间差,而不是依赖帧间隔假设固定的 16ms。这样可以保证动画在不同设备或标签页切换后依然平滑。下面是改进后的代码:
这里的关键点是用
performance.now()获取高精度时间戳,确保动画基于真实时间差来计算,而不是假设每帧间隔固定。这种写法能有效避免因标签页切换或其他性能问题导致的卡顿。还有一点需要注意,如果页面上有其他耗时任务(比如大量的 DOM 操作或者复杂的计算),也会影响动画流畅度。尽量把这些任务放到 Web Worker 中,或者用
setTimeout分片执行,给动画留出足够的主线程时间。