Several people asked why I need this. Here is the context: I have an animation (an endless loop that renders one frame after another). The output of each iteration needs to be synchronized with monitor refresh rate, otherwise tearing will happen. The way I am doing it right now is to use setTimeout(loop, 16)
within the loop
method. Its sort of working. The second parameter needs to be 1/(refresh rate), and that is why I asked this question.
Checking or changing your monitor's refresh rate is simple. If you're using Windows 10 or 11, press the Windows + I buttons to access the Settings menu (you can also open it from the Start menu). From there, click on Display Settings and then scroll down to Advanced Display Settings.
The default frame rate is based on the frame rate of the display (here also called "refresh rate"), which is set to 60 frames per second on most computers.
A frame rate is the speed at which the browser is able to recalculate, layout and paint content to the display. The frames per second, or fps, is how many frames can be repainted in one second. The goal frame rate for in web site computer graphics is 60fps.
You may have some luck on modern browsers using window.requestAnimationFrame
with a trivial callback that measures the time between successive invocations and from that calculate the FPS.
You should also be able to easily skip your render function every nth invocation to reduce the desired frame rate.
I put a rough example at http://jsfiddle.net/rBGPk/ - the math may be slightly wrong but it should be enough to show the general idea.
The solution below works by measuring the number of milliseconds between two consecutive animation frames.
Warning: It often returns an incorrect FPS because sometimes an animation frame is skipped when your CPU is busy with other tasks.
// Function that returns a Promise for the FPS
const getFPS = () =>
new Promise(resolve =>
requestAnimationFrame(t1 =>
requestAnimationFrame(t2 => resolve(1000 / (t2 - t1)))
)
)
// Calling the function to get the FPS
getFPS().then(fps => console.log(fps));
Tips
This is robust method, using the requestAnimationFrame method.
function calcFPS(opts){
var requestFrame = window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame;
if (!requestFrame) return true; // Check if "true" is returned;
// pick default FPS, show error, etc...
function checker(){
if (index--) requestFrame(checker);
else {
// var result = 3*Math.round(count*1000/3/(performance.now()-start));
var result = count*1000/(performance.now()- start);
if (typeof opts.callback === "function") opts.callback(result);
console.log("Calculated: "+result+" frames per second");
}
}
if (!opts) opts = {};
var count = opts.count||60, index = count, start = performance.now();
checker();
}
The higher the value of count
, the more accurate the value of the FPS, and the longer the FPS test will take.
Additional logic can be used to round to 15/12s, ie 24, 30, 48, 60 120... FPS.
Here's the compiled version (with rounding to 3 FPS):
function calcFPS(a){function b(){if(f--)c(b);else{var e=3*Math.round(1E3*d/3/(performance.now()-g));"function"===typeof a.callback&&a.callback(e);console.log("Calculated: "+e+" frames per second")}}var c=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame;if(!c)return!0;a||(a={});var d=a.count||60,f=d,g=performance.now();b()}
Used like so:
calcFPS(); // Only logs to console (you can remove the console log,
// making this call redundant)
calcFPS({count: 30}); // Manually set count (the test should take 500ms
// on a 60FPS monitor
calcFPS({callback: useFPS}); // Specify a callback so you can use the
// FPS number value
var FPS = 0, err = calcFPS({count: 120, callback: fps => FPS = fps});
if (err) FPS = 30;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With