Files
everything-is-suitable/everything-is-suitable-uniapp/src/utils/performanceMonitor.ts
T
zhangxiang 69da92b58b test: 修复所有已知问题并全面提高测试覆盖率至 90%
KNOWN-007: solarTime.ts 单元测试
KNOWN-008: 消除生产代码中 as any 类型断言
KNOWN-002: 工具层测试覆盖
KNOWN-003: lruCache 边界测试
KNOWN-004: templateService 分支覆盖(100%)
KNOWN-001: 6个业务组件测试
额外修复: searchOptimizer memoize bug, templateService 常量修改 bug

测试覆盖率: 75.71% -> 90.22%, 测试用例: 412 -> 671
2026-08-13 00:09:46 +08:00

136 lines
3.4 KiB
TypeScript

interface PerformanceMonitorMetric {
average: number
p95: number
p99: number
max: number
min: number
count: number
}
class PerformanceMonitor {
private metrics: Map<string, number[]> = new Map()
private readonly MAX_SAMPLES = 100
startMeasure(operation: string): () => void {
const startTime = performance.now()
return () => {
const endTime = performance.now()
const duration = endTime - startTime
this.recordMetric(operation, duration)
console.log(`[性能监控] ${operation}: ${duration.toFixed(2)}ms`)
}
}
recordMetric(operation: string, duration: number): void {
if (!this.metrics.has(operation)) {
this.metrics.set(operation, [])
}
const samples = this.metrics.get(operation)!
samples.push(duration)
if (samples.length > this.MAX_SAMPLES) {
samples.shift()
}
}
getAverage(operation: string): number {
const samples = this.metrics.get(operation)
if (!samples || samples.length === 0) {
return 0
}
const sum = samples.reduce((acc, val) => acc + val, 0)
return sum / samples.length
}
getP95(operation: string): number {
const samples = this.metrics.get(operation)
if (!samples || samples.length === 0) {
return 0
}
const sorted = [...samples].sort((a, b) => a - b)
const index = Math.floor(sorted.length * 0.95)
return sorted[index]
}
getP99(operation: string): number {
const samples = this.metrics.get(operation)
if (!samples || samples.length === 0) {
return 0
}
const sorted = [...samples].sort((a, b) => a - b)
const index = Math.floor(sorted.length * 0.99)
return sorted[index]
}
getMax(operation: string): number {
const samples = this.metrics.get(operation)
if (!samples || samples.length === 0) {
return 0
}
return Math.max(...samples)
}
getMin(operation: string): number {
const samples = this.metrics.get(operation)
if (!samples || samples.length === 0) {
return 0
}
return Math.min(...samples)
}
getMetrics(): Record<string, PerformanceMonitorMetric> {
const result: Record<string, PerformanceMonitorMetric> = {}
for (const [operation, samples] of this.metrics.entries()) {
result[operation] = {
average: this.getAverage(operation),
p95: this.getP95(operation),
p99: this.getP99(operation),
max: this.getMax(operation),
min: this.getMin(operation),
count: samples.length
}
}
return result
}
clearMetrics(): void {
this.metrics.clear()
}
clearOperationMetrics(operation: string): void {
this.metrics.delete(operation)
}
printReport(): void {
console.log('========== 性能监控报告 ==========')
const metrics = this.getMetrics()
for (const [operation, data] of Object.entries(metrics)) {
console.log(`\n${operation}:`)
console.log(` 平均耗时: ${data.average.toFixed(2)}ms`)
console.log(` P95耗时: ${data.p95.toFixed(2)}ms`)
console.log(` P99耗时: ${data.p99.toFixed(2)}ms`)
console.log(` 最大耗时: ${data.max.toFixed(2)}ms`)
console.log(` 最小耗时: ${data.min.toFixed(2)}ms`)
console.log(` 采样次数: ${data.count}`)
}
console.log('==================================')
}
}
const performanceMonitor = new PerformanceMonitor()
export default performanceMonitor