Можно ли узнать, какова частота кадров монитора в javascript?
- Во-первых, можно ли узнать
какова частота кадров монитора/частота обновления в
javascript (60 Гц для большинства ЖК-мониторов)?
- Во-вторых, есть ли способ
сказать, выполнить функцию после
каждые X кадров?
Несколько человек спросили, зачем мне это нужно. Вот контекст: у меня есть анимация (бесконечный цикл, который отображает один кадр за другим). Выход каждой итерации должен быть синхронизирован с частотой обновления монитора, иначе tearing произойдет. То, как я делаю это прямо сейчас, - это использовать setTimeout(loop, 16)
в методе loop
. Это своего рода работа. Второй параметр должен быть 1/(частота обновления), и именно поэтому я задал этот вопрос.
Ответы
Ответ 1
Возможно, вам повезло в современных браузерах, используя window.requestAnimationFrame
с тривиальным обратным вызовом, который измеряет время между последовательными вызовами и от того, что вычисляет FPS.
Вы также можете легко пропустить функцию рендеринга каждый n-й вызов, чтобы уменьшить желаемую частоту кадров.
Я привел пример на http://jsfiddle.net/rBGPk/ - математика может быть немного неправильной, но этого должно быть достаточно, чтобы показать общую идею.
Ответ 2
Приведенное ниже решение работает путем измерения количества миллисекунд между двумя последовательными кадрами анимации.
Предупреждение: он часто возвращает неправильный FPS, потому что иногда анимационный кадр пропускается, когда ваш процессор занят другими задачами.
// 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));
Ответ 3
Это надежный метод, используя метод 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;