检查JS中的FPS?

Cya*_*ime 35 html javascript html5 canvas

我如何检查我的JavaScript的fps?我正在使用它循环:

gameloopId = setInterval(gameLoop, 10);
Run Code Online (Sandbox Code Playgroud)

Phr*_*ogz 93

@Slaks的代码仅为您提供最后一帧的瞬时FPS,这可能会因打嗝而变化或误导.我更喜欢使用易于编写和计算的低通滤波器来消除快速瞬变并显示最近结果的合理伪平均值:

// The higher this value, the less the fps will reflect temporary variations
// A value of 1 will only keep the last value
var filterStrength = 20;
var frameTime = 0, lastLoop = new Date, thisLoop;

function gameLoop(){
  // ...
  var thisFrameTime = (thisLoop=new Date) - lastLoop;
  frameTime+= (thisFrameTime - frameTime) / filterStrength;
  lastLoop = thisLoop;
}

// Report the fps only every second, to only lightly affect measurements
var fpsOut = document.getElementById('fps');
setInterval(function(){
  fpsOut.innerHTML = (1000/frameTime).toFixed(1) + " fps";
},1000);
Run Code Online (Sandbox Code Playgroud)

此过滤器的"半衰期" - 从旧值中间移动到新的稳定值所需的帧数filterStrength*Math.log(2)(约为强度的70%).

例如,强度20将在中途移动到14帧的瞬时变化,在28帧中有3/4的路径,在46帧中有90%的路径,在92帧中有99%的路径.对于一个运行速度大约为30fps的系统,性能的突然剧烈变化将在半秒内显而易见,但仍然会"抛弃"单帧异常,因为它们只会将值偏移5%.

下面是一个~30fps游戏的不同过滤器强度的视觉比较,其瞬间下降到10fps,然后速度高达50fps.正如您所看到的,较低的过滤器值更快地反映了"良好"的变化,但也更容易受到临时打嗝的影响:
在此输入图像描述

最后,这是一个使用上面的代码来实际对"游戏"循环进行基准测试的例子.

  • @BennyNeugebauer以上内容是在Excel中创建的,只是因为它比一次性更容易[使用HTML5 Canvas进行漂亮的IIR绘图](http://phrogz.net/js/framerate-independent-low-pass-filter的.html). (3认同)

SLa*_*aks 28

gameLoop,看之间的区别new Date,并new Date从最后一个循环(它存储在一个变量).
换一种说法:

var lastLoop = new Date();
function gameLoop() { 
    var thisLoop = new Date();
    var fps = 1000 / (thisLoop - lastLoop);
    lastLoop = thisLoop;
    ...
}
Run Code Online (Sandbox Code Playgroud)

thisLoop - lastLoop 是两个循环之间传递的毫秒数.

  • 你可以用Date.now()取代新的Date,同样的东西,但更正确的imo (4认同)
  • @JacekDziurdzikowski 使用 `requestAnimationFrame` 比使用 `setInterval()` 或 `setTimeout()` 具有更好的性能,因为它会自动调整 fps 的时间。 (2认同)

NVR*_*VRM 9

我的2分钱:

对我比较优化很有用。当然,燃烧一些资源仅用于测试。

理想情况下,在使用事件、循环等时,您的应用程序帧速率应始终保持在 50 毫秒以下。这等于 20FPS。

人眼在 24 FPS 下感觉滞后,即1000 / 24 = 41ms

因此,一帧41 毫秒是最小的时间窗口,以保持自然的流畅性。应避免高于此值。

let be = Date.now(),fps=0,info='';
requestAnimationFrame(
    function loop(){
        let now = Date.now()
        fps = Math.round(1000 / (now - be))
        be = now
        requestAnimationFrame(loop)
        if (fps < 35){
          kFps.style.color = "red"
          kFps.textContent = fps 
        } if (fps >= 35 && fps <= 41) {
            kFps.style.color = "deepskyblue"
            kFps.textContent = fps + " FPS"
          } else {
            kFps.style.color = "black"
            kFps.textContent = fps + " FPS"
        }
        kpFps.value = fps;
        info+=(''+new Date()+' '+fps+'\n');
    }
 )
Run Code Online (Sandbox Code Playgroud)
<span id="kFps"></span>
<progress id="kpFps" value="0" min="0" max="100" style="vertical-align:middle"></progress>
<button onclick="try{console.clear();console.info(info)}catch{}">Statistics</button>
Run Code Online (Sandbox Code Playgroud)


只是一个测试循环来了解这个想法,50ms 间隔,应该保持平稳!

看到跳跃上方的进度条了吗?^

这些都是帧丢失,浏览器试图通过牺牲、跳到下一帧来跟上。应避免这些尖峰。下一个片段会消耗资源(即 FPS):

let t
for (let i=0;i<99999;i++){
  t = setTimeout(function(){
   console.log("I am burning your CPU! " + i)
   clearTimeout(t)
  },50)
  
}
Run Code Online (Sandbox Code Playgroud)


最新版本的调试器在录制时在选项卡中具有 FPS 计数器performance。这并不完美,因为它使测试过载。

在此输入图像描述