不能。requestAnimationFrame本身不返回FPS数值,仅在下一次重绘前执行回调;需用performance.now()记录时间戳、滑动窗口统计帧间隔并换算,才能得到稳定FPS值。

requestAnimationFrame 能直接拿到 FPS 吗?
不能。requestAnimationFrame 本身不返回帧率数值,它只负责在浏览器下一次重绘前执行回调——你得自己算时间差、统计帧数。常见误区是以为调用一次就能“获取 FPS”,其实它只是高精度计时的触发器,不是测量工具。
核心逻辑就一句:每秒统计多少次 requestAnimationFrame 回调被执行。但要注意:这个“每秒”不能简单用 setInterval(1000) 算,因为 JS 主线程阻塞、页面非激活、节流(如后台标签页)都会导致回调被跳过或延迟。
怎么用 requestAnimationFrame 实现稳定 FPS 统计?
推荐用滑动窗口法:记录最近 N 次回调的时间戳,用最新时间减去最早时间,再除以帧数。比固定 1 秒计数更抗抖动,尤其适合页面卡顿时仍能反映真实渲染节奏。
- 取最近 60 帧(约 1 秒满帧)足够平衡灵敏度和稳定性
- 每次
requestAnimationFrame触发时 push 当前performance.now()时间戳 - 若数组长度 > 60,shift 掉最老的时间戳
- 计算
(latest - oldest) / (frameCount - 1)得到平均单帧耗时,再取倒数 × 1000 即为 FPS
let timestamps = [];
function tick() {
const now = performance.now();
timestamps.push(now);
if (timestamps.length > 60) timestamps.shift();
<p>if (timestamps.length >= 2) {
const fps = Math.round(
(timestamps.length - 1) * 1000 / (now - timestamps[0])
);
console.log('FPS:', fps); // 或更新 DOM 显示
}
requestAnimationFrame(tick);
}
requestAnimationFrame(tick);为什么用 performance.now() 而不用 Date.now()?
performance.now() 提供亚毫秒级单调递增时间,不受系统时钟调整影响;Date.now() 可能因 NTP 校时跳变,导致帧间隔算出负值或极大异常值。尤其在长时运行或用户手动改系统时间时,Date.now() 会直接让 FPS 计算崩掉。
生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力: - 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面; - 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”; - 提及位于 `apps/console/src/featur
立即学习“前端免费学习笔记(深入)”;
另外注意:performance.now() 返回的是浮点数(单位 ms),做减法后保留小数参与 FPS 计算是必要的,四舍五入应放在最终显示环节,而非中间计算。
Chrome DevTools 里看到的 FPS 面板和代码算的一样吗?
不一样。DevTools 的 FPS 面板(Rendering → FPS Meter)统计的是**合成器线程提交的帧**,包含 GPU 渲染阶段;而 JS 里用 requestAnimationFrame 统计的是**主线程调度的帧回调次数**。当页面存在大量 CSS 动画、transform 动画或 offscreen canvas 渲染时,合成器可能仍在出帧,但 JS 回调被节流甚至暂停(比如页面切到后台),这时你代码里测到的 FPS 会掉到 0,而 DevTools 显示仍有 60 FPS。
所以:JS 测的是「你的 JS 是否跟得上刷新节奏」,不是「屏幕是否在刷」。真要定位卡顿,得结合 Performance 面板看主线程阻塞、Layout/Recalculate Style 耗时,而不是只盯一个数字。


















