You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于浏览器帧丢弃问题与requestAnimationFrame作用的技术问询

你的基础认知没有偏差:60Hz刷新率下,浏览器每帧的完整渲染预算约为16.67ms(1000ms/60),如果主线程被JS任务占用超过这个时长,就会错过当前帧的垂直同步(vsync)信号,导致该帧无法渲染,用户就会感知到卡顿。

问题1 滚动事件回调的卡顿分析

结论是:不会每次触发都恰好丢6帧,但一定会造成明显的可感知卡顿,实际丢帧数会略高于6帧。

  • 首先要明确:滚动事件的触发频率没有和渲染帧对齐,主流浏览器会在两次渲染的间隔内触发46次`scroll`事件,当第一个`scroll`事件触发、100ms的`handleScroll`开始执行时,主线程会被完全占用,后续触发的所有`scroll`事件、渲染任务、其他交互任务都会进入队列等待。等100ms回调执行完成后,主线程还需要处理队列中积压的任务,这部分额外耗时也会占用帧预算,所以60Hz下实际丢帧数一般在79帧区间。
  • 定性判断标准:只要滚动回调的执行时长超过30ms,普通用户就能感知到滚动粘滞感,超过100ms属于严重卡顿。
  • 定量分析方法:可以用Chrome DevTools的Performance面板录制滚动操作过程,查看主线程的任务瀑布流,宽度超过16.67ms的黄色块就是长任务,数该长任务覆盖了多少个vsync时间节点(面板中会用灰色竖线标注),就能得到准确的丢帧数量。
问题2 requestAnimationFrame的防丢帧逻辑

你的理解完全正确:如果传入requestAnimationFrame的回调本身执行耗时超过16.67ms,依然会不可避免地丢帧。requestAnimationFrame的作用不是完全避免丢帧,而是消除所有因执行时机不对导致的不必要丢帧,它的价值体现在这两点:

  1. 执行时机固定:requestAnimationFrame的回调会被浏览器统一安排在每帧渲染流程的最开始执行,你在回调中修改的样式、计算的动画状态,一定会被纳入当前帧的渲染pipeline,不会出现「用定时器/事件回调修改样式,结果刚好错过当前帧渲染时机,白白等到下一帧才更新」的无效丢帧。
  2. 天然和刷新率对齐:requestAnimationFrame的执行频率完全匹配显示器的刷新率,每帧最多执行一次回调。如果用setTimeout/setInterval实现动画,定时器间隔和刷新率不匹配时,会出现部分帧执行两次动画逻辑、部分帧完全不执行的跳帧问题,requestAnimationFrame从根源上避免了这种情况。

简单来说:requestAnimationFrame解决的是「代码性时机错误导致的丢帧」,无法解决「代码本身性能不足导致的丢帧」,后者需要你通过优化回调耗时来解决。


内容的提问来源于stack exchange,提问作者Joji

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 17:39:03