代碼
// 性能警報時間,單位:毫秒,超過這個時間會打印警報,可自定義
const ALARM_TIME = 200;
// requestAnimationFrame的id
let monitorFrameTimeId = null;
/**
* 開始監(jiān)控幀耗時
*/
function startMonitorFrameTime() {
stopMonitorFrameTime();
// 由于啟動監(jiān)控時當(dāng)前幀可能已經(jīng)過了一段時間了,所以等到下一幀開始再啟動性能監(jiān)控
// 如果優(yōu)先啟動監(jiān)控,也可以去掉外面這一層requestAnimationFrame
monitorFrameTimeId = requestAnimationFrame(() => {
console.log("啟動性能監(jiān)控");
// performance.now()拿到的時間比Date精度更高
let lastTime = performance.now();
monitorFrameTimeId = requestAnimationFrame(callback);
function callback() {
const now = performance.now();
const delta = now - lastTime;
lastTime = now;
if (delta >= ALARM_TIME) {
console.warn(`性能警報,當(dāng)前幀耗時:${delta.toFixed(2)}ms`);
}
monitorFrameTimeId = requestAnimationFrame(callback);
}
});
}
/**
* 停止監(jiān)控當(dāng)前幀耗時
*/
function stopMonitorFrameTime() {
if (monitorFrameTimeId != null) {
console.log("停止性能監(jiān)控");
cancelAnimationFrame(monitorFrameTimeId);
monitorFrameTimeId = null;
}
}
// 監(jiān)聽切換到后臺
// 由于切換到后臺會暫停網(wǎng)頁繪制,導(dǎo)致兩次requestAnimationFrame回調(diào)的時間被拉長,所以切后臺的時候停止箭頭
document.addEventListener("visibilitychange", function () {
// 判斷當(dāng)前頁面是否隱藏
// this指向了document,this.hidden等價于document.hidden,如果用了箭頭函數(shù)這里就不能用this了
if (this.hidden) {
console.log("切換到后臺");
stopMonitorFrameTime();
} else {
console.log("切換到前臺");
startMonitorFrameTime();
}
});
startMonitorFrameTime();
預(yù)覽

性能警報

前后臺切換
日志樣式也可以根據(jù)自己的喜好修改一下:
const titleStyle = [
`background: #d35400`,
"padding: 0.2em 0.2em 0.2em 0.2em",
`color: #ffffff`,
"font-size: 1em",
"border-radius: 0.2em 0 0 0.2em",
"font-family: SimHei",
].join("; ");
const contentStyle = [
`background: #e67e22`,
"padding: 0.2em 0.2em 0.2em 0.2em",
`color: #ffffff`,
"font-size: 1em",
"border-radius: 0 0.2em 0.2em 0",
"font-family: SimHei",
].join("; ");
console.log("%c%s%c%s", titleStyle, "性能管理器", contentStyle, `性能警報,當(dāng)前幀耗時:${delta.toFixed(2)}ms`);

性能警報

前后臺切換