Javascript 在 JS 中检查 FPS?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4787431/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 14:05:16  来源:igfitidea点击:

Check FPS in JS?

javascripthtmlcanvas

提问by CyanPrime

How would I check the fps of my javascript? I'm using this to loop:

我将如何检查我的 javascript 的 fps?我用它来循环:

gameloopId = setInterval(gameLoop, 10);

采纳答案by SLaks

In gameLoop, look at the difference between new Dateand new Datefrom the last loop (store it in a variable).
In other words:

在 中gameLoop,查看new Datenew Date上一个循环之间的差异(将其存储在变量中)。
换句话说:

var lastLoop = new Date();
function gameLoop() { 
    var thisLoop = new Date();
    var fps = 1000 / (thisLoop - lastLoop);
    lastLoop = thisLoop;
    ...
}

thisLoop - lastLoopis the number of milliseconds that passed between the two loops.

thisLoop - lastLoop是两个循环之间经过的毫秒数。

回答by Phrogz

The code by @Slaks gives you only the instantaneous FPS of the last frame, which may vary or be misleading with hiccups. I prefer to use an easy-to-write-and-compute low-pass filter to remove quick transients and display a reasonable pseudo-average of recent results:

@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);

The 'halflife' of this filter—the number of frames needed to move halfway from the old value to a new, stable value—is filterStrength*Math.log(2)(roughly 70% of the strength).

这个过滤器的“半衰期”——从旧值到新的稳定值的一半所需的帧数——是filterStrength*Math.log(2)(大约 70% 的强度)。

For example, a strength of 20will move halfway to an instantaneous change in 14 frames, 3/4 of the way there in 28 frames, 90% of the way there in 46 frames, and 99% of the way there in 92 frames. For a system running at about 30fps, a sudden, drastic shift in performance will be obvious in half a second, but will still 'throw away' single-frame anomalies as they will only shift the value by 5% of the difference.

例如,强度20会在 14 帧中移动到一半,在 28 帧中是 3/4,在 46 帧中是 90%,在 92 帧中是 99%。对于以大约 30fps 运行的系统,性能的突然剧烈变化在半秒内会很明显,但仍会“丢弃”单帧异常,因为它们只会将值偏移 5% 的差异。

Here is a visual comparison of different filter strengths for a ~30fps game that has a momentary dip to 10fps and then later speeds up to 50fps. As you can see, lower filter values more quickly reflect 'good' changes, but also are more susceptible to temporary hiccups:
enter image description here

这是一个 ~30fps 游戏的不同过滤器强度的视觉比较,该游戏暂时下降到 10fps,然后速度高达 50fps。如您所见,较低的过滤器值可以更快地反映“良好”的变化,但也更容易出现暂时的问题:
在此处输入图片说明

Finally, here is an exampleof using the above code to actually benchmark a 'game' loop.

最后,这是一个使用上述代码实际对“游戏”循环进行基准测试的示例

回答by sha1962

I use this to calculate fps

我用它来计算fps

  var GameCanvas = document.getElementById("gameCanvas");
  var GameContext = doContext(GameCanvas,"GameCanvas");
  var FPS = 0;
  var TimeNow;
  var TimeTaken;
  var ASecond = 1000;
  var FPSLimit = 25;
  var StartTime = Date.now();
  var TimeBefore = StartTime;
  var FrameTime = ASecond/FPSLimit;
  var State = { Title:0, Started:1, Paused:2, Over:3 };
  var GameState = State.Title;

  function gameLoop() {
    requestAnimationFrame(gameLoop);
    TimeNow = Date.now();
    TimeTaken = TimeNow - TimeBefore;

    if (TimeTaken >= FrameTime) {
      FPS++
      if((TimeNow - StartTime) >= ASecond){
        StartTime += ASecond;
        doFPS();
        FPS = 0;
      }

      switch(GameState){
        case State.Title :
          break;
        case State.Started :
          break;
        case State.Paused :
          break;
        case State.Over :
          break;
      }
      TimeBefore = TimeNow - (TimeTaken % FrameTime);
    }
  }

  Sprites.onload = function(){
    requestAnimationFrame(gameLoop);
  }

  function drawText(Context,_Color, _X, _Y, _Text, _Size){
    Context.font =  "italic "+ _Size +" bold";
    Context.fillStyle = _Color;
    Context.fillText(_Text, _X, _Y);
  }

  function doFPS()(
    drawText(GameContext,"black",10,24,"FPS : " + FPS,"24px");
  }

  function doContext(Canvas,Name){
    if (Canvas.getContext) {
      var Context = Canvas.getContext('2d');
      return Context;
    }else{
      alert( Name + ' not supported your Browser needs updating');
    }
  }

回答by davidmars

What about requestAnimationFrame?

什么requestAnimationFrame

var before,now,fps;
before=Date.now();
fps=0;
requestAnimationFrame(
    function loop(){
        now=Date.now();
        fps=Math.round(1000/(now-before));
        before=now;
        requestAnimationFrame(loop);
        console.log("fps",fps)
    }
 );

回答by NVRM

My 2 cents:

我的 2 美分:

Useful to me to compare optimizations. Burn a bit of ressources, of course, for testings only.

对我比较优化很有用。烧一些资源,当然,只是为了测试。

Ideally, your app frame rate should stay above 50 frames by seconds, at full usage, when using events, loops, etc.

理想情况下,在使用事件、循环等时,您的应用程序帧速率应保持在每秒 50 帧以上,完全使用。

Screens won't refresh above than 60hz, anyway, at least for now.

无论如何,屏幕刷新不会超过 60hz,至少现在是这样。

Humans feels lags under 24 FPS, this is 1000 / 24 = 41ms

人类感觉滞后于 24 FPS,这是1000 / 24 = 41ms

So, 41ms for a frame is the last critical lowest point, before freezes feelings.

所以,一帧的 41ms 是最后一个临界最低点,在冻结感情之前。

let be = Date.now(),fps=0;
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
    }
 )
<span id="kFps"></span>
<progress id="kpFps" value="0" min="0" max="100" style="vertical-align:middle"></progress>

Just a loop to get the idea, 50ms interval, should keep up smooth! See the progress bar jumping? This are frames loss, and browsers trying to keep up by sacrifice, by jumping to the next frame, we must avoid that!

只是一个循环来获得想法,50ms 间隔,应该保持流畅!看到进度条跳跃了吗?这是帧丢失,浏览器试图通过牺牲来跟上,跳到下一帧,我们必须避免这种情况!

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