fps计算方法 通过raf

import {
FPSMonitorOptions,
} from '../types';
import { BasePlugin, autoRegister } from '../base';
import { Weblogger } from '../../config/types';

const defaultOptions = {
// 更新间隔
interval: 10 * 1000,
// 浮点精度 0 取整
decimals: 2,
};

/*
回调函数执行次数通常是每秒60次,
但在大多数遵循W3C建议的浏览器中,
回调函数执行次数通常与浏览器屏幕刷新次数相匹配。
*/
function fakeRaf(callback: (...args: any[]) => void) {
return setTimeout(callback, 1000 / 16);
}
const fakeCaf = clearTimeout;

const raf = function (this: any, callback: (...args: any[]) => void) {
const fn = window.requestAnimationFrame
|| window.mozRequestAnimationFrame
|| window.webkitRequestAnimationFrame
|| fakeRaf;
return fn.call(this, callback);
};

const caf = function (this: any, handle: number)
{
const fn = window.cancelAnimationFrame
|| window.mozCancelAnimationFrame
|| window.webkitCancelAnimationFrame
|| fakeCaf;
return fn.call(this, handle);
};

export default class FPSMonitor extends BasePlugin {

static key = 'fpsMonitor';

private options = {
...defaultOptions,
};

private count = 0;

private fpsTickId!: number;

private loopId!: number;

private loopBeginTime!: number;

private loopEndTime!: number;

/**
* 兼容写法,如果在 Weblog 初始化设置 plugins 时,不需要设置 weblog
* @param weblog
*/
constructor(options?: FPSMonitorOptions)
constructor(weblog?: Weblogger | FPSMonitorOptions, options?: FPSMonitorOptions) {
super();
// 兼容处理
let opts;
if (options) {
opts = options;
} else if (weblog) {
if ((weblog as Weblogger).logger) {
this.apply(weblog as Weblogger);
} else {
opts = weblog;
}
}
Object.assign(this.options, options);
this.start();
}
destroy() {
this.stop();
}
start() {
// 1执行loop方法
this.loop();
// 2执行fpsTick方法
this.fpsTick();
}
fpsTick() {
// fpsId返回值是一个标识,没有什么意义。可以传caf来取消回调函数
this.fpsTickId = raf(() => {
this.count++;
// 随着屏幕更新帧画面的次数执行,count一直在增加+
this.fpsTick();
});
}
loop() {
// 开始时间
this.loopBeginTime = new Date().valueOf();
// 每一段间隔后,得到一个loopId
this.loopId = window.setTimeout(() => {
// 间隔后得到一个loopendtime
this.loopEndTime = new Date().valueOf();
// 计算fps
const fps = this.calculate();
// 上报fps
this.weblog.collect('CUSTOM', 'fps', { key: 'fps', value: fps });
// count重置为0
this.count = 0;
// 重新执行loop方法
this.loop();
}, this.options.interval);
}
stop() {
caf(this.fpsTickId);
window.clearTimeout(this.loopId);
}
calculate() {
// 计算fps的方法
// during是这次loopEnd的时间- loopBegin的时间,就是loop方法调用的时间间隔
const during = this.loopEndTime - this.loopBeginTime;

// runCount = 间隔时间/count次数
const runCount = during / this.count;

/*
fps = frames per second
= 一秒内的帧数/一秒的时间
= 一段时间内的帧数/一段时间


runCount = during / this.count
得到的是每个帧的时间.. (可以这样理解)

需要倒过来,用1000除一下
*/
return +(1000 / runCount).toFixed(this.options.decimals);
}
}
 
 
 
 
 
 
=============================================================

原理:

 

同时执行两个函数,

 

1. 在raf中不断的自增count,count自增,不断调用这个方法(计算总帧数)。

2. 在一个setTimeout的时间间隔中对fps进行计算,计算后,重置count为0,不断调用这个方法。

当fps计算出来的时候,就可以进行上报,比如这个时间间隔是10,那么就是每10秒上报一次计算一次平均fps

 

fps计算公式: count/during * 1000( 乘以1000是因为,是以秒为单位)

 

 

总结来说就是:

 

使用raf计算总帧数,然后除以during,得到的就是这个时间段内的fps。

 

setTimeout是在这个时间间隔内调用计算

posted @ 2021-11-11 18:24  hh9515  阅读(252)  评论(0)    收藏  举报