/** * 性能监控模块 * 用于追踪和记录页面性能指标 */ import { MONITOR_CONFIG } from './performance-config' class PerformanceMonitor { constructor() { this.metrics = { firstScreenLoadTime: 0, imageLoadStats: { total: 0, success: 0, failed: 0, totalTime: 0 }, pollingStats: { totalRequests: 0, successRequests: 0, failedRequests: 0, totalResponseTime: 0 }, animationStats: { fps: 0, frameCount: 0 } } this.startTime = 0 this.fpsTimer = null this.lastFrameTime = 0 this.isRunning = false } /** * 检查监控是否启用 * @returns {boolean} */ isEnabled() { // 如果设置了强制开关,使用强制开关的值 if (MONITOR_CONFIG.FORCE_ENABLE !== null) { return MONITOR_CONFIG.FORCE_ENABLE } // 否则使用默认的 ENABLED 配置 return MONITOR_CONFIG.ENABLED } /** * 开始监控 */ start() { if (!this.isEnabled()) { console.log('[性能监控] 监控已禁用') return } if (this.isRunning) { console.warn('[性能监控] 监控已在运行中') return } this.isRunning = true this.startTime = Date.now() console.log('[性能监控] 开始监控') if (MONITOR_CONFIG.TRACK_FPS) { this.startFPSTracking() } } /** * 停止监控 */ stop() { if (!this.isRunning) { return } if (this.fpsTimer) { // uni-app 兼容的取消动画帧 // #ifdef H5 cancelAnimationFrame(this.fpsTimer) // #endif // #ifndef H5 clearTimeout(this.fpsTimer) // #endif this.fpsTimer = null } this.isRunning = false console.log('[性能监控] 停止监控') // 如果配置了自动打印报告,则打印 if (MONITOR_CONFIG.AUTO_PRINT_REPORT && this.isEnabled()) { this.printReport() } } /** * 记录首屏加载时间 */ recordFirstScreenLoad() { if (!this.isEnabled() || !this.isRunning) return this.metrics.firstScreenLoadTime = Date.now() - this.startTime this.log('info', `首屏加载时间: ${this.metrics.firstScreenLoadTime}ms`) // 如果加载时间过长,发出警告 if (this.metrics.firstScreenLoadTime > 3000) { this.log('warn', `首屏加载时间过长: ${this.metrics.firstScreenLoadTime}ms`) } } /** * 记录图片加载 * @param {boolean} success - 是否成功 * @param {number} loadTime - 加载时间(毫秒) */ recordImageLoad(success, loadTime = 0) { if (!this.isEnabled() || !this.isRunning) return this.metrics.imageLoadStats.total++ if (success) { this.metrics.imageLoadStats.success++ this.metrics.imageLoadStats.totalTime += loadTime } else { this.metrics.imageLoadStats.failed++ } // 计算成功率 const successRate = (this.metrics.imageLoadStats.success / this.metrics.imageLoadStats.total * 100).toFixed(2) const avgLoadTime = this.metrics.imageLoadStats.success > 0 ? (this.metrics.imageLoadStats.totalTime / this.metrics.imageLoadStats.success).toFixed(0) : 0 this.log('debug', `图片加载统计 - 成功率: ${successRate}%, 平均加载时间: ${avgLoadTime}ms`) // 如果失败率过高,发出警告 if (this.metrics.imageLoadStats.failed / this.metrics.imageLoadStats.total > 0.3) { this.log('warn', `图片加载失败率过高: ${(this.metrics.imageLoadStats.failed / this.metrics.imageLoadStats.total * 100).toFixed(2)}%`) } } /** * 记录轮询请求 * @param {boolean} success - 是否成功 * @param {number} responseTime - 响应时间(毫秒) */ recordPollingRequest(success, responseTime = 0) { if (!this.isEnabled() || !this.isRunning) return this.metrics.pollingStats.totalRequests++ if (success) { this.metrics.pollingStats.successRequests++ this.metrics.pollingStats.totalResponseTime += responseTime } else { this.metrics.pollingStats.failedRequests++ } // 计算平均响应时间 const avgResponseTime = this.metrics.pollingStats.successRequests > 0 ? (this.metrics.pollingStats.totalResponseTime / this.metrics.pollingStats.successRequests).toFixed(0) : 0 this.log('debug', `轮询统计 - 平均响应时间: ${avgResponseTime}ms`) // 如果响应时间过长,发出警告 if (responseTime > 5000) { this.log('warn', `轮询响应时间过长: ${responseTime}ms`) } } /** * 开始追踪 FPS */ startFPSTracking() { if (!this.isEnabled()) return let frameCount = 0 let lastTime = Date.now() const trackFrame = () => { frameCount++ const currentTime = Date.now() // 每秒计算一次 FPS if (currentTime - lastTime >= 1000) { this.metrics.animationStats.fps = frameCount this.metrics.animationStats.frameCount += frameCount this.log('debug', `当前 FPS: ${frameCount}`) // 如果 FPS 过低,发出警告 if (frameCount < 30) { this.log('warn', `FPS 过低: ${frameCount}`) } frameCount = 0 lastTime = currentTime } if (this.isRunning) { // uni-app 兼容的动画帧请求 // #ifdef H5 this.fpsTimer = requestAnimationFrame(trackFrame) // #endif // #ifndef H5 this.fpsTimer = setTimeout(trackFrame, 16) // 约 60fps // #endif } } trackFrame() } /** * 获取性能报告 * @returns {Object} 性能指标对象 */ getReport() { const report = { ...this.metrics, imageLoadSuccessRate: this.metrics.imageLoadStats.total > 0 ? (this.metrics.imageLoadStats.success / this.metrics.imageLoadStats.total * 100).toFixed(2) + '%' : '0%', avgImageLoadTime: this.metrics.imageLoadStats.success > 0 ? (this.metrics.imageLoadStats.totalTime / this.metrics.imageLoadStats.success).toFixed(0) + 'ms' : '0ms', pollingSuccessRate: this.metrics.pollingStats.totalRequests > 0 ? (this.metrics.pollingStats.successRequests / this.metrics.pollingStats.totalRequests * 100).toFixed(2) + '%' : '0%', avgPollingResponseTime: this.metrics.pollingStats.successRequests > 0 ? (this.metrics.pollingStats.totalResponseTime / this.metrics.pollingStats.successRequests).toFixed(0) + 'ms' : '0ms' } return report } /** * 打印性能报告 */ printReport() { if (!this.isEnabled()) return const report = this.getReport() console.log('========== 性能监控报告 ==========') console.log(`首屏加载时间: ${report.firstScreenLoadTime}ms`) console.log(`图片加载统计:`) console.log(` - 总数: ${report.imageLoadStats.total}`) console.log(` - 成功: ${report.imageLoadStats.success}`) console.log(` - 失败: ${report.imageLoadStats.failed}`) console.log(` - 成功率: ${report.imageLoadSuccessRate}`) console.log(` - 平均加载时间: ${report.avgImageLoadTime}`) console.log(`轮询统计:`) console.log(` - 总请求数: ${report.pollingStats.totalRequests}`) console.log(` - 成功: ${report.pollingStats.successRequests}`) console.log(` - 失败: ${report.pollingStats.failedRequests}`) console.log(` - 成功率: ${report.pollingSuccessRate}`) console.log(` - 平均响应时间: ${report.avgPollingResponseTime}`) if (MONITOR_CONFIG.TRACK_FPS) { console.log(`动画统计:`) console.log(` - 当前 FPS: ${report.animationStats.fps}`) console.log(` - 总帧数: ${report.animationStats.frameCount}`) } console.log('==================================') } /** * 重置统计数据 */ reset() { this.metrics = { firstScreenLoadTime: 0, imageLoadStats: { total: 0, success: 0, failed: 0, totalTime: 0 }, pollingStats: { totalRequests: 0, successRequests: 0, failedRequests: 0, totalResponseTime: 0 }, animationStats: { fps: 0, frameCount: 0 } } this.startTime = Date.now() console.log('[性能监控] 统计数据已重置') } /** * 启用监控(运行时控制) */ enable() { MONITOR_CONFIG.FORCE_ENABLE = true console.log('[性能监控] 已手动启用') if (!this.isRunning) { this.start() } } /** * 禁用监控(运行时控制) */ disable() { MONITOR_CONFIG.FORCE_ENABLE = false console.log('[性能监控] 已手动禁用') if (this.isRunning) { this.stop() } } /** * 日志输出 * @param {string} level - 日志级别 * @param {string} message - 日志消息 */ log(level, message) { if (!this.isEnabled()) return const levels = ['debug', 'info', 'warn', 'error'] const configLevel = MONITOR_CONFIG.LOG_LEVEL if (levels.indexOf(level) >= levels.indexOf(configLevel)) { const prefix = '[性能监控]' switch (level) { case 'debug': console.log(prefix, message) break case 'info': console.info(prefix, message) break case 'warn': console.warn(prefix, message) break case 'error': console.error(prefix, message) break } } } } // 创建单例实例 const performanceMonitor = new PerformanceMonitor() export default performanceMonitor // 导出常用方法 export const { start, stop, recordFirstScreenLoad, recordImageLoad, recordPollingRequest, getReport, printReport, reset, enable, disable, isEnabled } = performanceMonitor