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

如何解决requestAnimationFrame失去页面焦点后帧率骤降问题?

解决requestAnimationFrame失焦后帧率下降的问题

问题根源

浏览器为了节省系统资源,在页面失焦(如窗口最小化、切换标签页)时会大幅降低requestAnimationFrame的调用频率,甚至直接暂停调用。再次聚焦页面时,elapsed会累积成一个远大于fpsInterval的数值,你的代码虽尝试调整then的值,但帧率计算依赖全局累积的frameCount和sinceStart,会因失焦期间的空白时间导致计算出的帧率骤降;同时过大的elapsed会让绘制逻辑在短时间内连续执行多次,表现为帧率突然下降的卡顿感。

解决方案及修改后的代码

通过三点优化即可解决该问题:

  1. 监听页面可见性变化,重新聚焦时重置时间基准then,确保从当前时间开始计算帧间隔
  2. 限制elapsed的最大值,避免单次循环处理过多累积时间,防止短时间内执行多次绘制逻辑
  3. 改用最近帧的时间差计算实时帧率,避免依赖全局累积值导致的误差

修改后的代码:

var stop = false;
var fpsInterval, startTime, now, then, elapsed;
// 用于计算实时帧率的临时变量
var lastFpsCalcTime = 0;
var framesSinceLastCalc = 0;

startAnimating(30);

function startAnimating(fps) {
    fpsInterval = 1000 / fps;
    then = window.performance.now();
    startTime = then;
    lastFpsCalcTime = then;
    console.log(startTime);
    animate();
    
    // 监听页面可见性变化,聚焦时重置时间基准
    document.addEventListener('visibilitychange', function() {
        if (!document.hidden) {
            then = window.performance.now();
            lastFpsCalcTime = then;
            framesSinceLastCalc = 0;
        }
    });
}


function animate(newtime) {
    if (stop) {
        return;
    }

    requestAnimationFrame(animate);

    now = newtime;
    elapsed = now - then;

    // 限制elapsed最大值,避免单次处理过多累积时间
    if (elapsed > fpsInterval * 2) {
        elapsed = fpsInterval;
        then = now - elapsed;
    }

    if (elapsed > fpsInterval) {
        then = now - (elapsed % fpsInterval);

        // 此处编写你的绘制逻辑

        // 优化帧率计算:每1秒统计一次最近的帧数
        framesSinceLastCalc++;
        var timeSinceLastCalc = now - lastFpsCalcTime;
        if (timeSinceLastCalc >= 1000) {
            var currentFps = Math.round((framesSinceLastCalc / timeSinceLastCalc) * 1000 * 100) / 100;
            console.log(currentFps + " fps.");
            lastFpsCalcTime = now;
            framesSinceLastCalc = 0;
        }
    }
}

关键优化点说明

  • 页面可见性监听:页面从失焦状态恢复时,直接将then重置为当前时间,避免用失焦期间累积的大时间差计算后续帧间隔
  • elapsed上限限制:防止单次循环处理几十秒的累积时间,避免短时间内连续执行几十次绘制逻辑导致页面卡顿
  • 实时帧率计算:不再依赖全局累积的帧计数和时间,而是每1秒统计一次最近的帧数,计算出的帧率更准确,也不会因失焦空白时间出现异常值

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 23:45:40