/** * 分块对比性能测试脚本 * 用于测试和验证分块对比预览的性能改进 */ class ChunkComparePerformanceTester { constructor() { this.testResults = []; this.isRunning = false; } /** * 运行完整的性能测试套件 */ async runFullTestSuite() { if (this.isRunning) { console.warn('[PerformanceTest] 测试正在进行中,请等待完成'); return; } this.isRunning = true; console.log('[PerformanceTest] 开始运行性能测试套件'); try { const results = { testTime: new Date().toISOString(), browser: this.getBrowserInfo(), device: this.getDeviceInfo(), tests: {} }; // 测试不同数量的分块 const chunkCounts = [5, 10, 20, 50, 100]; for (const count of chunkCounts) { console.log(`[PerformanceTest] 测试 ${count} 个分块的性能`); results.tests[`chunks_${count}`] = await this.testChunkRendering(count); // 让浏览器有时间清理 await this.delay(1000); } // 测试内存使用情况 results.memoryTest = this.testMemoryUsage(); // 测试滚动性能 results.scrollTest = await this.testScrollPerformance(); // 生成测试报告 this.generateTestReport(results); console.log('[PerformanceTest] 性能测试套件完成'); return results; } catch (error) { console.error('[PerformanceTest] 测试过程中出错:', error); } finally { this.isRunning = false; } } /** * 测试分块渲染性能 */ async testChunkRendering(chunkCount) { const testData = this.generateTestData(chunkCount); const container = this.createTestContainer(); // 测试原有渲染方法 const originalResult = await this.testOriginalRendering(testData, container); // 清理 container.innerHTML = ''; await this.delay(100); // 测试优化后的渲染方法 const optimizedResult = await this.testOptimizedRendering(testData, container); // 清理 container.remove(); const improvement = { renderTime: { original: originalResult.renderTime, optimized: optimizedResult.renderTime, improvement: ((originalResult.renderTime - optimizedResult.renderTime) / originalResult.renderTime * 100).toFixed(2) + '%' }, memoryUsage: { original: originalResult.memoryUsage, optimized: optimizedResult.memoryUsage, reduction: originalResult.memoryUsage > 0 ? ((originalResult.memoryUsage - optimizedResult.memoryUsage) / originalResult.memoryUsage * 100).toFixed(2) + '%' : 'N/A' }, domNodes: { original: originalResult.domNodes, optimized: optimizedResult.domNodes, reduction: ((originalResult.domNodes - optimizedResult.domNodes) / originalResult.domNodes * 100).toFixed(2) + '%' } }; console.log(`[PerformanceTest] ${chunkCount}个分块测试结果:`, improvement); return improvement; } /** * 生成测试数据 */ generateTestData(chunkCount) { const ocrChunks = []; const translatedChunks = []; for (let i = 0; i < chunkCount; i++) { // 生成不同长度的测试内容 const contentLength = Math.floor(Math.random() * 1000) + 200; // 200-1200字符 const ocrContent = this.generateTestContent(contentLength, 'ocr', i); const transContent = this.generateTestContent(contentLength, 'translation', i); ocrChunks.push(ocrContent); translatedChunks.push(transContent); } return { ocrChunks, translatedChunks, images: [] }; } /** * 生成测试内容 */ generateTestContent(length, type, index) { const headings = [ '# 主要标题', '## 次要标题', '### 三级标题' ]; const paragraphs = [ '这是一段测试文本,用于验证分块对比功能的性能表现。', '本段包含**粗体文字**和*斜体文字*,以及`代码片段`。', '测试内容包括数学公式:$E = mc^2$,以及更复杂的公式:$$\\int_{-\\infty}^{\\infty} e^{-x^2} dx = \\sqrt{\\pi}$$', '这里有一个代码块:\n```javascript\nfunction test() {\n console.log("Hello World");\n}\n```', '列表项目:\n- 第一项\n- 第二项\n- 第三项', '表格测试:\n| 列1 | 列2 | 列3 |\n|-----|-----|-----|\n| 值1 | 值2 | 值3 |' ]; let content = `${headings[index % headings.length]} (${type} #${index + 1})\n\n`; while (content.length < length) { content += paragraphs[Math.floor(Math.random() * paragraphs.length)] + '\n\n'; } return content.substring(0, length); } /** * 创建测试容器 */ createTestContainer() { const container = document.createElement('div'); container.id = 'performance-test-container'; container.style.cssText = ` position: absolute; top: -10000px; left: -10000px; width: 1000px; height: 600px; overflow: hidden; `; document.body.appendChild(container); return container; } /** * 测试原有渲染方法 */ async testOriginalRendering(testData, container) { const startTime = performance.now(); const startMemory = this.getMemoryUsage(); // 模拟原有的同步渲染 let html = '
'; for (let i = 0; i < testData.ocrChunks.length; i++) { html += `

分块 ${i + 1}

${this.renderMarkdownSync(testData.ocrChunks[i])}
${this.renderMarkdownSync(testData.translatedChunks[i])}
`; } html += '
'; container.innerHTML = html; const endTime = performance.now(); const endMemory = this.getMemoryUsage(); const domNodes = container.querySelectorAll('*').length; return { renderTime: endTime - startTime, memoryUsage: endMemory - startMemory, domNodes: domNodes }; } /** * 测试优化后的渲染方法 */ async testOptimizedRendering(testData, container) { const startTime = performance.now(); const startMemory = this.getMemoryUsage(); // 使用优化器进行渲染 if (window.ChunkCompareOptimizer && window.ChunkCompareOptimizer.instance) { const optimizedHTML = window.ChunkCompareOptimizer.instance.optimizeChunkComparison( testData.ocrChunks, testData.translatedChunks, { images: testData.images, isOriginalFirst: true } ); container.innerHTML = optimizedHTML; // 等待异步渲染完成 await this.waitForOptimizedRendering(container); } else { // 回退到预览模式 let html = '
'; for (let i = 0; i < Math.min(testData.ocrChunks.length, 5); i++) { html += `

分块 ${i + 1}

${this.getContentPreview(testData.ocrChunks[i])}
点击加载完整内容
`; } html += '
'; container.innerHTML = html; } const endTime = performance.now(); const endMemory = this.getMemoryUsage(); const domNodes = container.querySelectorAll('*').length; return { renderTime: endTime - startTime, memoryUsage: endMemory - startMemory, domNodes: domNodes }; } /** * 等待优化后的渲染完成 */ async waitForOptimizedRendering(container) { let maxWait = 5000; // 最多等待5秒 const interval = 100; while (maxWait > 0) { const loadingIndicators = container.querySelectorAll('.chunk-loading-indicator'); if (loadingIndicators.length === 0) { break; } await this.delay(interval); maxWait -= interval; } } /** * 同步渲染Markdown(简化版) */ renderMarkdownSync(content) { if (!content) return ''; // 简化的Markdown渲染,避免复杂的异步操作 return content .replace(/\*\*(.*?)\*\*/g, '$1') .replace(/\*(.*?)\*/g, '$1') .replace(/`(.*?)`/g, '$1') .replace(/\n/g, '
'); } /** * 获取内容预览 */ getContentPreview(content) { if (!content) return '(空内容)'; return content.length > 100 ? content.substring(0, 100) + '...' : content; } /** * 测试内存使用情况 */ testMemoryUsage() { if (!performance.memory) { return { error: '浏览器不支持内存监控', supported: false }; } const memory = performance.memory; return { supported: true, usedJSHeapSize: (memory.usedJSHeapSize / 1024 / 1024).toFixed(2) + ' MB', totalJSHeapSize: (memory.totalJSHeapSize / 1024 / 1024).toFixed(2) + ' MB', jsHeapSizeLimit: (memory.jsHeapSizeLimit / 1024 / 1024).toFixed(2) + ' MB', usage: ((memory.usedJSHeapSize / memory.jsHeapSizeLimit) * 100).toFixed(2) + '%' }; } /** * 测试滚动性能 */ async testScrollPerformance() { const container = document.querySelector('.chunk-compare-container'); if (!container) { return { error: '未找到分块对比容器' }; } const scrollTests = []; const scrollDistance = 100; const testCount = 10; for (let i = 0; i < testCount; i++) { const startTime = performance.now(); // 模拟滚动 container.scrollTop += scrollDistance; // 等待渲染完成 await new Promise(resolve => requestAnimationFrame(resolve)); const endTime = performance.now(); scrollTests.push(endTime - startTime); } // 重置滚动位置 container.scrollTop = 0; const avgScrollTime = scrollTests.reduce((a, b) => a + b, 0) / scrollTests.length; const maxScrollTime = Math.max(...scrollTests); const minScrollTime = Math.min(...scrollTests); return { averageTime: avgScrollTime.toFixed(2) + 'ms', maxTime: maxScrollTime.toFixed(2) + 'ms', minTime: minScrollTime.toFixed(2) + 'ms', testCount: testCount }; } /** * 获取内存使用量 */ getMemoryUsage() { if (performance.memory) { return performance.memory.usedJSHeapSize; } return 0; } /** * 获取浏览器信息 */ getBrowserInfo() { const ua = navigator.userAgent; let browser = 'Unknown'; if (ua.indexOf('Chrome') > -1) browser = 'Chrome'; else if (ua.indexOf('Firefox') > -1) browser = 'Firefox'; else if (ua.indexOf('Safari') > -1) browser = 'Safari'; else if (ua.indexOf('Edge') > -1) browser = 'Edge'; return { name: browser, userAgent: ua, vendor: navigator.vendor, language: navigator.language }; } /** * 获取设备信息 */ getDeviceInfo() { return { platform: navigator.platform, hardwareConcurrency: navigator.hardwareConcurrency || 'Unknown', deviceMemory: navigator.deviceMemory || 'Unknown', screenResolution: `${screen.width}x${screen.height}`, viewportSize: `${window.innerWidth}x${window.innerHeight}` }; } /** * 生成测试报告 */ generateTestReport(results) { console.group('[PerformanceTest] 性能测试报告'); console.log('测试时间:', results.testTime); console.log('浏览器信息:', results.browser); console.log('设备信息:', results.device); console.group('分块渲染测试结果:'); Object.entries(results.tests).forEach(([testName, result]) => { console.group(testName); console.log('渲染时间改善:', result.renderTime.improvement); console.log('内存使用减少:', result.memoryUsage.reduction); console.log('DOM节点减少:', result.domNodes.reduction); console.groupEnd(); }); console.groupEnd(); console.log('内存测试:', results.memoryTest); console.log('滚动性能测试:', results.scrollTest); console.groupEnd(); // 将结果保存到 localStorage localStorage.setItem('chunkComparePerformanceResults', JSON.stringify(results)); // 显示用户友好的报告 this.showUserReport(results); } /** * 显示用户友好的测试报告 */ showUserReport(results) { const reportEl = document.createElement('div'); reportEl.className = 'performance-report-modal'; reportEl.innerHTML = `

分块对比性能测试报告

测试时间: ${new Date(results.testTime).toLocaleString()}
浏览器: ${results.browser.name}
总体评价: ${this.calculateOverallGrade(results)}

性能改进详情

${this.generateResultsHTML(results.tests)}
`; // 添加样式 const style = document.createElement('style'); style.id = 'performance-report-style'; // 添加ID以便后续清理 style.textContent = ` .performance-report-modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 10000; } .report-overlay { background: rgba(0,0,0,0.5); width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; } .report-content { background: white; max-width: 600px; max-height: 80vh; overflow-y: auto; border-radius: 8px; padding: 24px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); } .report-summary { margin: 16px 0; border: 1px solid #e2e8f0; border-radius: 6px; padding: 16px; } .summary-item { display: flex; justify-content: space-between; margin-bottom: 8px; } .performance-grade { font-weight: bold; color: #059669; } .test-results { margin: 16px 0; } .result-item { padding: 8px; border-bottom: 1px solid #f1f5f9; } .report-actions { display: flex; gap: 12px; justify-content: flex-end; margin-top: 20px; } .report-actions button { padding: 8px 16px; border: 1px solid #d1d5db; border-radius: 4px; background: white; cursor: pointer; } .report-actions button:first-child { background: #f3f4f6; } .report-actions button:last-child { background: #3b82f6; color: white; border-color: #3b82f6; } `; document.head.appendChild(style); document.body.appendChild(reportEl); // 添加事件监听器 const closeBtn = document.getElementById('close-performance-report'); const exportBtn = document.getElementById('export-performance-report'); const overlay = reportEl.querySelector('.report-overlay'); // 关闭按钮事件 closeBtn.addEventListener('click', () => { this.closeReport(); }); // 导出按钮事件 exportBtn.addEventListener('click', () => { this.exportReport(); }); // 点击遮罩层关闭 overlay.addEventListener('click', (e) => { if (e.target === overlay) { this.closeReport(); } }); // ESC键关闭 const escHandler = (e) => { if (e.key === 'Escape') { this.closeReport(); document.removeEventListener('keydown', escHandler); } }; document.addEventListener('keydown', escHandler); } /** * 关闭性能报告 */ closeReport() { const reportEl = document.querySelector('.performance-report-modal'); const styleEl = document.getElementById('performance-report-style'); if (reportEl) { reportEl.remove(); } if (styleEl) { styleEl.remove(); } } /** * 计算总体评分 */ calculateOverallGrade(results) { let totalImprovement = 0; let testCount = 0; Object.values(results.tests).forEach(test => { const improvement = parseFloat(test.renderTime.improvement); if (!isNaN(improvement)) { totalImprovement += improvement; testCount++; } }); const avgImprovement = testCount > 0 ? totalImprovement / testCount : 0; if (avgImprovement >= 50) return '优秀 (A)'; if (avgImprovement >= 30) return '良好 (B)'; if (avgImprovement >= 10) return '一般 (C)'; return '需改进 (D)'; } /** * 生成结果HTML */ generateResultsHTML(tests) { return Object.entries(tests).map(([testName, result]) => `
${testName.replace('chunks_', '')}个分块:
渲染速度提升: ${result.renderTime.improvement}
内存使用减少: ${result.memoryUsage.reduction}
DOM节点减少: ${result.domNodes.reduction}
`).join(''); } /** * 导出测试报告 */ exportReport() { const results = localStorage.getItem('chunkComparePerformanceResults'); if (!results) { alert('没有可导出的测试结果'); return; } const blob = new Blob([results], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `chunk-compare-performance-${Date.now()}.json`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); } /** * 延迟函数 */ delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } } // 创建全局测试实例 window.ChunkComparePerformanceTester = new ChunkComparePerformanceTester(); // 添加控制台快捷命令 console.log('%c分块对比性能测试器已加载', 'color: #059669; font-weight: bold'); console.log('使用 window.ChunkComparePerformanceTester.runFullTestSuite() 运行完整测试'); // 如果在开发环境,自动运行测试 if (window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1') { // 页面加载完成后自动运行测试 window.addEventListener('load', () => { setTimeout(() => { if (document.querySelector('.chunk-compare-container')) { console.log('[PerformanceTest] 检测到分块对比页面,自动运行性能测试'); window.ChunkComparePerformanceTester.runFullTestSuite(); } }, 2000); }); }