|
| 1 | +/* eslint-disable no-console */ |
| 2 | +/* eslint-disable no-restricted-syntax */ |
| 3 | +/* eslint-disable no-restricted-globals */ |
| 4 | + |
| 5 | +declare module globalThis { |
| 6 | + let doProfile: boolean |
| 7 | + let recordTime: boolean |
| 8 | + let times: Record<string, number[]> |
| 9 | +} |
| 10 | + |
| 11 | +globalThis.recordTime = true |
| 12 | +globalThis.doProfile = false |
| 13 | + |
| 14 | +export const defer = () => new Promise(r => requestIdleCallback(r)) |
| 15 | + |
| 16 | +const times: Record<string, number[]> = (globalThis.times = {}) |
| 17 | + |
| 18 | +export function wrap( |
| 19 | + id: string, |
| 20 | + fn: (...args: any[]) => any, |
| 21 | +): (...args: any[]) => Promise<void> { |
| 22 | + return async (...args) => { |
| 23 | + if (!globalThis.recordTime) { |
| 24 | + return fn(...args) |
| 25 | + } |
| 26 | + |
| 27 | + document.body.classList.remove('done') |
| 28 | + |
| 29 | + const { doProfile } = globalThis |
| 30 | + await defer() |
| 31 | + |
| 32 | + doProfile && console.profile(id) |
| 33 | + const start = performance.now() |
| 34 | + fn(...args) |
| 35 | + |
| 36 | + await defer() |
| 37 | + const time = performance.now() - start |
| 38 | + const prevTimes = times[id] || (times[id] = []) |
| 39 | + prevTimes.push(time) |
| 40 | + |
| 41 | + const { min, max, median, mean, std } = compute(prevTimes) |
| 42 | + const msg = |
| 43 | + `${id}: min: ${min} / ` + |
| 44 | + `max: ${max} / ` + |
| 45 | + `median: ${median}ms / ` + |
| 46 | + `mean: ${mean}ms / ` + |
| 47 | + `time: ${time.toFixed(2)}ms / ` + |
| 48 | + `std: ${std} ` + |
| 49 | + `over ${prevTimes.length} runs` |
| 50 | + doProfile && console.profileEnd(id) |
| 51 | + console.log(msg) |
| 52 | + const timeEl = document.getElementById('time')! |
| 53 | + timeEl.textContent = msg |
| 54 | + |
| 55 | + document.body.classList.add('done') |
| 56 | + } |
| 57 | +} |
| 58 | + |
| 59 | +function compute(array: number[]) { |
| 60 | + const n = array.length |
| 61 | + const max = Math.max(...array) |
| 62 | + const min = Math.min(...array) |
| 63 | + const mean = array.reduce((a, b) => a + b) / n |
| 64 | + const std = Math.sqrt( |
| 65 | + array.map(x => Math.pow(x - mean, 2)).reduce((a, b) => a + b) / n, |
| 66 | + ) |
| 67 | + const median = array.slice().sort((a, b) => a - b)[Math.floor(n / 2)] |
| 68 | + return { |
| 69 | + max: round(max), |
| 70 | + min: round(min), |
| 71 | + mean: round(mean), |
| 72 | + std: round(std), |
| 73 | + median: round(median), |
| 74 | + } |
| 75 | +} |
| 76 | + |
| 77 | +function round(n: number) { |
| 78 | + return +n.toFixed(2) |
| 79 | +} |
0 commit comments