forked from reformcollective/library
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathuseTrackFrameTime.ts
93 lines (77 loc) · 2.22 KB
/
useTrackFrameTime.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import { useEffect } from "react"
import { isBrowser } from "./deviceDetection"
const MAX_FRAME_TIME_MS = 0.5
const canTrackFrames = isBrowser && window.location.href.includes("localhost")
const systemRequestFrame = canTrackFrames ? requestAnimationFrame : undefined
const requests: FrameRequestCallback[] = []
let startIndex = 0
if (canTrackFrames) {
console.info("tracking frame times")
window.requestAnimationFrame = (request) => {
requests.push(request)
return startIndex + requests.length - 1
}
window.cancelAnimationFrame = (id: number) => {
const indexToClear = id - startIndex
if (indexToClear >= 0) {
requests[indexToClear] = () => {
// this function replaces the callback, so it's a no-op
}
}
}
}
const lastThirtySeconds: number[] = []
const onFrame = (time: number) => {
systemRequestFrame?.(onFrame)
const requestsCopy = [...requests]
startIndex += requests.length
requests.length = 0
const frameStart = performance.now()
for (const r of requestsCopy) {
if (typeof r === "function") r(time)
}
const frameEnd = performance.now()
if (frameStart > 5 * 1000) {
const frameTime = frameEnd - frameStart
lastThirtySeconds.push(frameTime)
setTimeout(() => {
lastThirtySeconds.shift()
}, 30 * 1000)
}
}
export default function useTrackFrameTime() {
useEffect(() => {
if (canTrackFrames) systemRequestFrame?.(onFrame)
}, [])
useEffect(() => {
if (!canTrackFrames) return
const logFrameTimes = () => {
if (lastThirtySeconds.length === 0) return
let average = 0
let max = Number.NEGATIVE_INFINITY
let min = Number.POSITIVE_INFINITY
for (const time of lastThirtySeconds) {
average += time
max = Math.max(max, time)
min = Math.min(min, time)
}
average /= lastThirtySeconds.length
// console.info(
// `Last 30s Frame Times: ${average.toFixed(2)}ms (min: ${min.toFixed(
// 2
// )}ms, max: ${max.toFixed(2)}ms)`
// )
if (average > MAX_FRAME_TIME_MS) {
console.warn(
`
High frame times in the last 30s. Check your performance!
Average: ${average.toFixed(2)}ms
Min: ${min.toFixed(2)}ms
Max: ${max.toFixed(2)}ms`,
)
}
}
const interval = setInterval(logFrameTimes, 10_000)
return () => clearInterval(interval)
}, [])
}