有几个人问我为什么需要这个。这是上下文:我有一个动画(一个接一个渲染一个帧的无限循环)。每次迭代的输出需要与监视器刷新率同步,否则将发生tearing。我现在这样做的方法是在setTimeout(loop, 16)
方法中使用loop
。它的工作。第二个参数需要是1 /(刷新率),这就是我问这个问题的原因。
答案 0 :(得分:11)
现代浏览器使用window.requestAnimationFrame
可能会有一些运气,其中有一个简单的回调来衡量连续调用之间的时间以及计算FPS的时间。
您还应该能够在每次调用时轻松跳过渲染功能,以降低所需的帧速率。
我在http://jsfiddle.net/rBGPk/做了一个粗略的例子 - 数学可能有点错误,但它应该足以表明一般的想法。
答案 1 :(得分:4)
以下解决方案的工作原理是测量两个连续动画帧之间的毫秒数。
警告:它通常会返回不正确的FPS,因为当您的CPU忙于执行其他任务时,有时会跳过动画帧。
Master

<强>提示强>
答案 2 :(得分:0)
这是一种强大的方法,使用requestAnimationFrame方法。
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();
}
count
的值越高,FPS的值越准确,FPS测试的时间就越长。
可以使用额外的逻辑来舍入到15 / 12s,即24,30,48,60 120 ... FPS。
这是编译版本(四舍五入到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()}
像这样使用:
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;
答案 3 :(得分:0)
计算重绘之间的时间间隔:
const getRepaintInterval = () => {
return new Promise((resolve) => {
requestAnimationFrame((t1) => {
requestAnimationFrame((t2) => {
resolve(t2 - t1);
});
});
});
};
或者计算选定秒内的FPS:
const getFps = () => new Promise(resolve => {
let repaint = 0;
const start = performance.now();
const withRepaint = () => {
requestAnimationFrame(() => {
if ((performance.now() - start) < 1000) {
repaint += 1;
withRepaint();
} else {
resolve(repaint);
}
});
};
withRepaint();
});
或使用 start
和 end
计算 FPS:
const fpsHandler = () => {
let repaint;
let stop;
let ret;
let start;
const init = () => {
ret = undefined;
stop = false;
repaint = 0;
start = performance.now();
};
init();
const withRepaint = () => {
requestAnimationFrame(() => {
if (!stop) {
repaint += 1;
withRepaint();
}
});
};
return {
start: () => {
init();
withRepaint();
},
end: () => {
stop = true;
if (!ret) ret = repaint / ((performance.now() - start) / 1000);
return ret;
}
}
};
const { start, end } = fpsHandler();
答案 4 :(得分:0)
根据之前解释使用 requestAnimationFrame
并测量帧之间的时间差的一些答案,这里是一个使用 requestAnimationFrame
和已发送到回调的时间戳的解决方案。否则就没有理由运行单独的 performance.now()
函数。
var previousTimestamp, divInterval, divFPS;
const raf = window.requestAnimationFrame || window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
const rafLoop = timestamp => {
let interval = timestamp - previousTimestamp;
let fps = 1000 / interval;
divInterval.innerHTML = `Interval: ${interval}`;
divFPS.innerHTML = `FPS: ${fps}`;
previousTimestamp = timestamp;
raf(rafLoop);
};
divInterval = document.getElementById('interval');
divFPS = document.getElementById('fps');
// This is run first to set the previousTimestamp variable with an initial value, and then call the rafLoop function.
raf(timestamp => {
previousTimestamp = timestamp;
raf(rafLoop);
});
<div id="interval"></div>
<div id="fps"></div>
另请参阅 https://codepen.io/sassano/pen/wvgxxMp 以获取此代码段源自的带有动画的另一个示例。