| const express = require('express'); |
| const path = require('path'); |
| const fs = require('fs'); |
| const { exec } = require('child_process'); |
| const LargeFileHandler = require('./src/largeFile'); |
| const xmlJsonHandler = require('./src/xmlJson'); |
| const performanceMonitor = require('./src/performance'); |
| const CoreApiDemo = require('./src/coreApiDemo'); |
|
|
| const app = express(); |
| const PORT = 7860; |
|
|
| const DATA_DIR = path.join(__dirname, 'data'); |
|
|
| |
| if (!fs.existsSync(DATA_DIR)) { |
| fs.mkdirSync(DATA_DIR); |
| } |
|
|
| const LARGE_FILE_PATH = path.join(DATA_DIR, 'large_data.csv'); |
| const XML_FILE_PATH = path.join(DATA_DIR, 'data.xml'); |
| const LARGE_JSON_PATH = path.join(DATA_DIR, 'large_data.json'); |
|
|
| |
| global.isDemoRunning = false; |
|
|
| |
| async function runLargeFileDemo() { |
| console.log('=== 1. 大文件流式处理演示 ==='); |
| try { |
| const largeFileHandler = new LargeFileHandler(LARGE_FILE_PATH); |
| const lineCount = 100000; |
| console.log(`正在生成测试数据 (${lineCount} 行)...`); |
| await largeFileHandler.generateTestFile(lineCount); |
| console.log('开始流式处理...'); |
| await largeFileHandler.processFileStream(); |
| logMemoryUsage(); |
| } catch (err) { |
| console.error('发生错误:', err); |
| } |
| } |
|
|
| |
| async function runXmlDemo() { |
| console.log('=== 2. XML 处理演示 ==='); |
| try { |
| const xmlContent = xmlJsonHandler.generateXml(1000); |
| fs.writeFileSync(XML_FILE_PATH, xmlContent); |
| console.log(`XML 文件已保存: ${XML_FILE_PATH}`); |
| const parsedXml = xmlJsonHandler.parseXml(xmlContent); |
| console.log('XML 解析完成'); |
| logMemoryUsage(); |
| } catch (err) { |
| console.error('发生错误:', err); |
| } |
| } |
|
|
| |
| async function runJsonDemo() { |
| console.log('=== 3. JSON 大文件流式处理演示 ==='); |
| try { |
| console.log('正在生成 JSON 数据...'); |
| await xmlJsonHandler.generateLargeJson(LARGE_JSON_PATH, 10000); |
| console.log('开始流式解析 JSON...'); |
| await xmlJsonHandler.processLargeJsonStream(LARGE_JSON_PATH); |
| logMemoryUsage(); |
| } catch (err) { |
| console.error('发生错误:', err); |
| } |
| } |
|
|
| |
| async function runCoreApiDemo() { |
| const coreDemo = new CoreApiDemo(DATA_DIR); |
| await coreDemo.run(); |
| } |
|
|
| function logMemoryUsage() { |
| const used = process.memoryUsage(); |
| console.log('Memory Usage:'); |
| for (let key in used) { |
| console.log(`${key}: ${Math.round(used[key] / 1024 / 1024 * 100) / 100} MB`); |
| } |
| } |
|
|
| |
| app.get('/', (req, res) => { |
| res.send(` |
| <!DOCTYPE html> |
| <html> |
| <head> |
| <title>Node.js Performance Demo</title> |
| <meta charset="utf-8"> |
| <style> |
| body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; background: #f0f2f5; padding: 40px; color: #333; } |
| .container { max-width: 900px; margin: 0 auto; background: #fff; padding: 30px; border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); } |
| h1 { color: #2c3e50; margin-bottom: 20px; border-bottom: 2px solid #eee; padding-bottom: 10px; } |
| .controls { margin-bottom: 20px; display: grid; grid-template-columns: repeat(2, 1fr); gap: 15px; } |
| button { padding: 15px; font-size: 16px; cursor: pointer; background: #007bff; color: white; border: none; border-radius: 5px; transition: background 0.3s; font-weight: bold; } |
| button:hover { background: #0056b3; } |
| button:disabled { background: #ccc; cursor: not-allowed; } |
| .btn-core { background: #6610f2; } |
| .btn-core:hover { background: #520dc2; } |
| .btn-system { background: #28a745; } |
| .btn-system:hover { background: #218838; } |
| .btn-clear { background: #6c757d; } |
| .btn-clear:hover { background: #5a6268; } |
| #output { background: #1e1e1e; color: #d4d4d4; padding: 20px; border-radius: 5px; font-family: "Menlo", "Monaco", "Courier New", monospace; height: 500px; overflow-y: auto; white-space: pre-wrap; font-size: 14px; line-height: 1.5; border: 1px solid #333; } |
| .status { margin-top: 10px; font-style: italic; color: #666; } |
| </style> |
| </head> |
| <body> |
| <div class="container"> |
| <h1>Node.js Performance Demo</h1> |
| <div class="controls"> |
| <button onclick="runDemo('large-file')">📄 1. 大文件流式处理</button> |
| <button onclick="runDemo('xml')">🏷️ 2. XML 解析处理</button> |
| <button onclick="runDemo('json')">📦 3. JSON 流式解析</button> |
| <button onclick="getSystemInfo()" class="btn-system">🖥️ 4. 系统信息 (child_process)</button> |
| <button onclick="runDemo('core-api')" class="btn-core">🛠️ 5. 核心 API 综合演示</button> |
| <button onclick="clearOutput()" class="btn-clear">🗑 清空输出</button> |
| </div> |
| <div id="output">点击上方按钮开始测试...</div> |
| <div id="status" class="status"></div> |
| </div> |
| |
| <script> |
| const outputDiv = document.getElementById('output'); |
| const statusDiv = document.getElementById('status'); |
| let isRunning = false; |
| |
| function log(msg, isError = false) { |
| if (outputDiv.innerHTML === '点击上方按钮开始测试...') { |
| outputDiv.innerHTML = ''; |
| } |
| const span = document.createElement('div'); |
| span.textContent = msg; |
| if (isError) span.style.color = '#ff6b6b'; |
| outputDiv.appendChild(span); |
| outputDiv.scrollTop = outputDiv.scrollHeight; |
| } |
| |
| function clearOutput() { |
| outputDiv.innerHTML = '点击上方按钮开始测试...'; |
| statusDiv.textContent = ''; |
| } |
| |
| function runDemo(type) { |
| if (isRunning) return; |
| |
| isRunning = true; |
| updateButtons(true); |
| statusDiv.textContent = '正在运行演示...'; |
| |
| const eventSource = new EventSource('/api/run-demo?type=' + type); |
| |
| eventSource.onmessage = function(event) { |
| try { |
| const data = JSON.parse(event.data); |
| if (data.type === 'log') { |
| log(data.message); |
| } else if (data.type === 'error') { |
| log(data.message, true); |
| } else if (data.type === 'end') { |
| eventSource.close(); |
| isRunning = false; |
| updateButtons(false); |
| statusDiv.textContent = '演示完成'; |
| } |
| } catch (e) { |
| console.error('Error parsing SSE data', e); |
| } |
| }; |
| |
| eventSource.onerror = function(err) { |
| console.error('EventSource failed:', err); |
| eventSource.close(); |
| isRunning = false; |
| updateButtons(false); |
| statusDiv.textContent = '连接中断'; |
| log('Error: Connection to server lost.', true); |
| }; |
| } |
| |
| function updateButtons(disabled) { |
| const btns = document.querySelectorAll('button:not(.btn-clear)'); |
| btns.forEach(btn => btn.disabled = disabled); |
| } |
| |
| async function getSystemInfo() { |
| if (isRunning) return; |
| statusDiv.textContent = '正在获取系统信息...'; |
| try { |
| const res = await fetch('/api/system-info'); |
| const text = await res.text(); |
| log('\\n=== 4. 系统信息 ==='); |
| log(text); |
| statusDiv.textContent = '获取成功'; |
| } catch (e) { |
| log('Error fetching system info: ' + e.message, true); |
| } |
| } |
| </script> |
| </body> |
| </html> |
| `); |
| }); |
|
|
| |
| app.get('/api/run-demo', async (req, res) => { |
| const type = req.query.type; |
|
|
| if (global.isDemoRunning) { |
| res.writeHead(200, { |
| 'Content-Type': 'text/event-stream', |
| 'Cache-Control': 'no-cache', |
| 'Connection': 'keep-alive' |
| }); |
| res.write(`data: ${JSON.stringify({ type: 'error', message: 'Demo is already running. Please wait.' })}\n\n`); |
| res.write(`data: ${JSON.stringify({ type: 'end' })}\n\n`); |
| return res.end(); |
| } |
|
|
| res.writeHead(200, { |
| 'Content-Type': 'text/event-stream', |
| 'Cache-Control': 'no-cache', |
| 'Connection': 'keep-alive' |
| }); |
|
|
| global.isDemoRunning = true; |
|
|
| |
| const send = (type, message) => { |
| res.write(`data: ${JSON.stringify({ type, message })}\n\n`); |
| }; |
|
|
| |
| const originalConsoleLog = console.log; |
| const originalConsoleError = console.error; |
|
|
| console.log = (...args) => { |
| const msg = args.map(arg => (typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg))).join(' '); |
| send('log', msg); |
| originalConsoleLog.apply(console, args); |
| }; |
|
|
| console.error = (...args) => { |
| const msg = args.map(arg => (typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg))).join(' '); |
| send('error', msg); |
| originalConsoleError.apply(console, args); |
| }; |
|
|
| try { |
| switch (type) { |
| case 'large-file': |
| await runLargeFileDemo(); |
| break; |
| case 'xml': |
| await runXmlDemo(); |
| break; |
| case 'json': |
| await runJsonDemo(); |
| break; |
| case 'core-api': |
| await runCoreApiDemo(); |
| break; |
| default: |
| console.log('未知的任务类型'); |
| } |
| } catch (e) { |
| console.error('Unhandled error:', e); |
| } finally { |
| |
| console.log = originalConsoleLog; |
| console.error = originalConsoleError; |
| global.isDemoRunning = false; |
| |
| send('end', 'Done'); |
| res.end(); |
| } |
| }); |
|
|
| |
| app.get('/api/system-info', (req, res) => { |
| exec('uname -a && echo "\\nDisk Usage:" && df -h | head -n 5', (error, stdout, stderr) => { |
| if (error) { |
| res.status(500).send(`Error: ${error.message}`); |
| return; |
| } |
| res.send(stdout); |
| }); |
| }); |
|
|
| app.listen(PORT, () => { |
| console.log(`Server is running on http://localhost:${PORT}`); |
| }); |
|
|