浏览器事件循环与内存管理可视化

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>浏览器事件循环、内存管理与渲染模拟 - 优化布局版</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }
        
        body {
            background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);
            color: #fff;
            min-height: 100vh;
            padding: 20px;
        }
        
        .container {
            max-width: 1800px;
            margin: 0 auto;
        }
        
        header {
            text-align: center;
            padding: 20px 0;
            margin-bottom: 20px;
        }
        
        h1 {
            font-size: 2.2rem;
            margin-bottom: 10px;
            text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
        }
        
        .subtitle {
            font-size: 1.1rem;
            opacity: 0.9;
            max-width: 800px;
            margin: 0 auto;
            line-height: 1.6;
        }
        
        .main-layout {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 20px;
            margin-bottom: 20px;
        }
        
        .panel {
            background: rgba(255, 255, 255, 0.1);
            backdrop-filter: blur(10px);
            border-radius: 15px;
            padding: 20px;
            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
            border: 1px solid rgba(255, 255, 255, 0.2);
        }
        
        .panel h2 {
            margin-bottom: 15px;
            padding-bottom: 10px;
            border-bottom: 1px solid rgba(255, 255, 255, 0.3);
            display: flex;
            align-items: center;
        }
        
        .panel h2 .icon {
            margin-right: 10px;
            font-size: 1.4rem;
        }
        
        .controls {
            display: flex;
            flex-wrap: wrap;
            gap: 10px;
            margin-bottom: 20px;
        }
        
        button {
            background: rgba(255, 255, 255, 0.2);
            border: none;
            color: white;
            padding: 10px 15px;
            border-radius: 8px;
            cursor: pointer;
            transition: all 0.3s ease;
            font-weight: 500;
            display: flex;
            align-items: center;
            gap: 8px;
        }
        
        button:hover {
            background: rgba(255, 255, 255, 0.3);
            transform: translateY(-2px);
        }
        
        button:active {
            transform: translateY(0);
        }
        
        .speed-controls {
            display: flex;
            align-items: center;
            gap: 10px;
            margin-top: 15px;
        }
        
        .speed-controls label {
            font-weight: 500;
        }
        
        .speed-controls input {
            width: 150px;
        }
        
        .code-editor {
            background: rgba(0, 0, 0, 0.4);
            padding: 20px;
            border-radius: 10px;
            margin-bottom: 20px;
            height: 100%;
            display: flex;
            flex-direction: column;
        }
        
        .code-input {
            width: 100%;
            flex: 1;
            background: rgba(0, 0, 0, 0.5);
            color: white;
            border: 1px solid rgba(255, 255, 255, 0.2);
            border-radius: 5px;
            padding: 15px;
            font-family: 'Courier New', monospace;
            resize: none;
            margin-bottom: 15px;
            font-size: 1rem;
            line-height: 1.5;
        }
        
        .code-controls {
            display: flex;
            gap: 10px;
        }
        
        .memory-queues-container {
            display: grid;
            grid-template-rows: 1fr 1fr;
            gap: 20px;
            height: 100%;
        }
        
        .memory-container {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 20px;
        }
        
        .memory-panel {
            background: rgba(0, 0, 0, 0.3);
            border-radius: 10px;
            padding: 15px;
        }
        
        .memory-panel h3 {
            margin-bottom: 10px;
            display: flex;
            align-items: center;
            justify-content: space-between;
        }
        
        .stack {
            display: flex;
            flex-direction: column-reverse;
            gap: 5px;
            min-height: 150px;
        }
        
        .stack-frame {
            background: rgba(255, 255, 255, 0.15);
            padding: 10px;
            border-radius: 8px;
            border-left: 4px solid #4CAF50;
        }
        
        .stack-frame.active {
            background: rgba(76, 175, 80, 0.3);
            box-shadow: 0 0 10px rgba(76, 175, 80, 0.5);
        }
        
        .heap {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
            gap: 10px;
            min-height: 150px;
        }
        
        .heap-object {
            background: rgba(255, 255, 255, 0.15);
            padding: 10px;
            border-radius: 8px;
            border-left: 4px solid #2196F3;
            text-align: center;
            position: relative;
            overflow: hidden;
        }
        
        .heap-object.referenced::after {
            content: '';
            position: absolute;
            top: 0;
            right: 0;
            width: 10px;
            height: 10px;
            background: #FF9800;
            border-radius: 50%;
        }
        
        .heap-object.garbage {
            opacity: 0.5;
            background: rgba(255, 0, 0, 0.2);
        }
        
        .queues-container {
            display: grid;
            grid-template-columns: 1fr 1fr 1fr;
            gap: 20px;
        }
        
        .queue {
            background: rgba(0, 0, 0, 0.3);
            border-radius: 10px;
            padding: 15px;
        }
        
        .queue h3 {
            margin-bottom: 10px;
            display: flex;
            align-items: center;
            justify-content: space-between;
        }
        
        .task {
            background: rgba(255, 255, 255, 0.15);
            padding: 10px;
            border-radius: 8px;
            margin-bottom: 8px;
            display: flex;
            align-items: center;
            transition: all 0.3s ease;
            position: relative;
            overflow: hidden;
        }
        
        .task.micro {
            border-left: 4px solid #4CAF50;
        }
        
        .task.macro {
            border-left: 4px solid #2196F3;
        }
        
        .task.animation {
            border-left: 4px solid #FF9800;
        }
        
        .task.executing {
            background: rgba(255, 255, 255, 0.3);
            transform: scale(1.02);
            box-shadow: 0 0 10px rgba(255, 255, 255, 0.5);
        }
        
        .task.completed {
            opacity: 0.7;
            transform: scale(0.98);
        }
        
        .task-icon {
            margin-right: 10px;
            font-size: 1.2rem;
        }
        
        .task-progress {
            position: absolute;
            bottom: 0;
            left: 0;
            height: 3px;
            background: rgba(255, 255, 255, 0.7);
            width: 0%;
            transition: width 0.1s linear;
        }
        
        .render-container {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 20px;
            margin-bottom: 20px;
        }
        
        .render-area {
            height: 200px;
            background: rgba(0, 0, 0, 0.3);
            border-radius: 10px;
            display: flex;
            align-items: center;
            justify-content: center;
            position: relative;
            overflow: hidden;
        }
        
        .render-box {
            width: 100px;
            height: 100px;
            background: linear-gradient(45deg, #ff0080, #00ff80);
            border-radius: 10px;
            transition: all 0.5s ease;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-weight: bold;
            text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
        }
        
        .render-box.rendering {
            animation: renderAnimation 0.8s ease;
        }
        
        @keyframes renderAnimation {
            0% { transform: scale(0.8) rotate(0deg); opacity: 0.5; }
            50% { transform: scale(1.1) rotate(180deg); opacity: 1; }
            100% { transform: scale(1) rotate(360deg); opacity: 1; }
        }
        
        .event-loop {
            display: flex;
            justify-content: center;
            align-items: center;
            position: relative;
        }
        
        .loop-circle {
            width: 300px;
            height: 300px;
            border: 3px dashed rgba(255, 255, 255, 0.5);
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            position: relative;
            animation: rotate 20s linear infinite;
        }
        
        .loop-step {
            position: absolute;
            width: 80px;
            height: 80px;
            background: rgba(255, 255, 255, 0.1);
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            flex-direction: column;
            text-align: center;
            padding: 10px;
            transition: all 0.3s ease;
        }
        
        .loop-step.active {
            background: rgba(255, 255, 255, 0.3);
            box-shadow: 0 0 15px rgba(255, 255, 255, 0.5);
        }
        
        .loop-step-1 {
            top: -40px;
            left: 50%;
            transform: translateX(-50%);
        }
        
        .loop-step-2 {
            bottom: -40px;
            left: 50%;
            transform: translateX(-50%);
        }
        
        .loop-step-3 {
            left: -40px;
            top: 50%;
            transform: translateY(-50%);
        }
        
        .loop-step-4 {
            right: -40px;
            top: 50%;
            transform: translateY(-50%);
        }
        
        @keyframes rotate {
            from { transform: rotate(0deg); }
            to { transform: rotate(360deg); }
        }
        
        .output-container {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 20px;
        }
        
        .output-panel {
            background: rgba(0, 0, 0, 0.3);
            border-radius: 10px;
            padding: 15px;
            height: 300px;
            display: flex;
            flex-direction: column;
        }
        
        .output-panel h3 {
            margin-bottom: 10px;
            display: flex;
            align-items: center;
            justify-content: space-between;
        }
        
        .console-output {
            background: rgba(0, 0, 0, 0.5);
            border-radius: 5px;
            padding: 10px;
            flex: 1;
            overflow-y: auto;
            font-family: 'Courier New', monospace;
            font-size: 0.9rem;
            line-height: 1.5;
        }
        
        .console-line {
            margin-bottom: 5px;
        }
        
        .console-line.log {
            color: #fff;
        }
        
        .console-line.error {
            color: #ff6b6b;
        }
        
        .console-line.warn {
            color: #ffd93d;
        }
        
        .log-container {
            max-height: 300px;
            overflow-y: auto;
            background: rgba(0, 0, 0, 0.3);
            border-radius: 10px;
            padding: 15px;
        }
        
        .log-entry {
            padding: 8px 0;
            border-bottom: 1px solid rgba(255, 255, 255, 0.1);
            display: flex;
            align-items: center;
        }
        
        .log-time {
            color: #FFD700;
            margin-right: 10px;
            font-family: 'Courier New', monospace;
        }
        
        .log-message.micro {
            color: #4CAF50;
        }
        
        .log-message.macro {
            color: #2196F3;
        }
        
        .log-message.animation {
            color: #FF9800;
        }
        
        .log-message.render {
            color: #E91E63;
        }
        
        .log-message.memory {
            color: #9C27B0;
        }
        
        .stats {
            display: grid;
            grid-template-columns: repeat(4, 1fr);
            gap: 15px;
            margin-top: 20px;
        }
        
        .stat-card {
            background: rgba(255, 255, 255, 0.1);
            padding: 15px;
            border-radius: 10px;
            text-align: center;
        }
        
        .stat-value {
            font-size: 1.8rem;
            font-weight: bold;
            margin: 5px 0;
        }
        
        .stat-label {
            font-size: 0.8rem;
            opacity: 0.8;
        }
        
        @media (max-width: 1400px) {
            .main-layout {
                grid-template-columns: 1fr;
            }
            
            .memory-queues-container {
                grid-template-rows: auto;
            }
            
            .queues-container {
                grid-template-columns: 1fr;
            }
            
            .memory-container {
                grid-template-columns: 1fr;
            }
            
            .render-container {
                grid-template-columns: 1fr;
            }
            
            .output-container {
                grid-template-columns: 1fr;
            }
            
            .stats {
                grid-template-columns: repeat(2, 1fr);
            }
        }
        
        @media (max-width: 768px) {
            .controls {
                flex-direction: column;
            }
            
            .stats {
                grid-template-columns: 1fr;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <!-- 标题 -->
        <header>
            <h1>浏览器事件循环、内存管理与渲染模拟</h1>
            <p class="subtitle">可视化展示浏览器事件循环机制、内存管理(调用栈、堆)和渲染过程的完整执行流程。支持自定义JavaScript代码模拟。</p>
        </header>
        
        <!-- 控制面板 -->
        <div class="panel">
            <h2><span class="icon">⚙️</span> 控制面板</h2>
            <div class="controls">
                <button id="add-microtask">
                    <span>⚡</span> 添加微任务
                </button>
                <button id="add-macrotask">
                    <span>⏰</span> 添加宏任务
                </button>
                <button id="add-animation">
                    <span>🎬</span> 添加动画任务
                </button>
                <button id="start-execution">
                    <span>▶️</span> 开始执行
                </button>
                <button id="pause-execution">
                    <span>⏸️</span> 暂停执行
                </button>
                <button id="reset-all">
                    <span>🔄</span> 重置模拟
                </button>
            </div>
            
            <div class="speed-controls">
                <label for="execution-speed">执行速度:</label>
                <input type="range" id="execution-speed" min="1" max="10" value="5">
                <span id="speed-value">中等</span>
            </div>
            
            <div class="stats">
                <div class="stat-card">
                    <div class="stat-label">已执行任务</div>
                    <div class="stat-value" id="executed-tasks">0</div>
                </div>
                <div class="stat-card">
                    <div class="stat-label">队列中任务</div>
                    <div class="stat-value" id="queued-tasks">3</div>
                </div>
                <div class="stat-card">
                    <div class="stat-label">渲染次数</div>
                    <div class="stat-value" id="render-count">0</div>
                </div>
                <div class="stat-card">
                    <div class="stat-label">堆对象数</div>
                    <div class="stat-value" id="heap-objects">0</div>
                </div>
            </div>
        </div>
        
        <!-- 主内容区域 -->
        <div class="main-layout">
            <!-- 左侧:代码编辑器 -->
            <div class="panel">
                <h2><span class="icon">💻</span> 自定义代码模拟</h2>
                <div class="code-editor">
                    <textarea class="code-input" id="code-input" placeholder="粘贴或输入JavaScript代码...">// 示例代码
console.log('脚本开始');

setTimeout(() => {
    console.log('setTimeout回调');
}, 0);

Promise.resolve().then(() => {
    console.log('Promise.then回调');
});

requestAnimationFrame(() => {
    console.log('requestAnimationFrame回调');
});

let user = { name: '张三', age: 30 };
let data = [1, 2, 3, 4, 5];

console.log('脚本结束');</textarea>
                    <div class="code-controls">
                        <button id="parse-code">
                            <span>🔍</span> 解析代码
                        </button>
                        <button id="load-example">
                            <span>📋</span> 加载示例
                        </button>
                    </div>
                </div>
            </div>
            
            <!-- 右侧:内存管理和任务队列 -->
            <div class="memory-queues-container">
                <!-- 内存管理 -->
                <div class="panel">
                    <h2><span class="icon">🧠</span> 内存管理</h2>
                    <div class="memory-container">
                        <div class="memory-panel">
                            <h3>调用栈 (Call Stack) <span id="stack-size">1</span></h3>
                            <div class="stack" id="call-stack">
                                <div class="stack-frame active">
                                    <strong>全局执行上下文</strong>
                                    <div>变量: 全局变量</div>
                                </div>
                            </div>
                        </div>
                        
                        <div class="memory-panel">
                            <h3>堆 (Heap) <span id="heap-size">0</span></h3>
                            <div class="heap" id="heap-memory"></div>
                        </div>
                    </div>
                </div>
                
                <!-- 任务队列 -->
                <div class="panel">
                    <h2><span class="icon">📊</span> 任务队列</h2>
                    <div class="queues-container">
                        <div class="queue">
                            <h3>宏任务队列 <span id="macro-count">1</span></h3>
                            <div id="macro-queue">
                                <div class="task macro">
                                    <span class="task-icon">⏰</span>
                                    <span>初始脚本执行</span>
                                    <div class="task-progress"></div>
                                </div>
                            </div>
                        </div>
                        
                        <div class="queue">
                            <h3>微任务队列 <span id="micro-count">0</span></h3>
                            <div id="micro-queue"></div>
                        </div>
                        
                        <div class="queue">
                            <h3>动画帧队列 <span id="animation-count">0</span></h3>
                            <div id="animation-queue"></div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        
        <!-- 渲染模拟 -->
        <div class="render-container">
            <div class="panel">
                <h2><span class="icon">🖥️</span> 渲染模拟</h2>
                <div class="render-area">
                    <div class="render-box" id="render-box">
                        渲染区域
                    </div>
                </div>
            </div>
            
            <div class="panel">
                <h2><span class="icon">🔄</span> 事件循环</h2>
                <div class="event-loop">
                    <div class="loop-circle">
                        <div class="loop-step loop-step-1" id="loop-step-1">
                            <strong>执行宏任务</strong>
                        </div>
                        <div class="loop-step loop-step-2" id="loop-step-2">
                            <strong>执行微任务</strong>
                        </div>
                        <div class="loop-step loop-step-3" id="loop-step-3">
                            <strong>执行动画回调</strong>
                        </div>
                        <div class="loop-step loop-step-4" id="loop-step-4">
                            <strong>渲染页面</strong>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        
        <!-- 输出区域 -->
        <div class="output-container">
            <div class="panel">
                <h2><span class="icon">📝</span> 执行日志</h2>
                <div class="log-container" id="log-container">
                    <div class="log-entry">
                        <span class="log-time">00:00:00</span>
                        <span class="log-message">模拟器已初始化,准备执行任务</span>
                    </div>
                </div>
            </div>
            
            <div class="panel">
                <h2><span class="icon">📄</span> 控制台输出</h2>
                <div class="output-panel">
                    <div class="console-output" id="console-output">
                        <div class="console-line log">控制台输出区域...</div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script>
        // 任务队列
        const macroQueue = document.getElementById('macro-queue');
        const microQueue = document.getElementById('micro-queue');
        const animationQueue = document.getElementById('animation-queue');
        const renderBox = document.getElementById('render-box');
        
        // 内存管理
        const callStack = document.getElementById('call-stack');
        const heapMemory = document.getElementById('heap-memory');
        
        // 计数显示
        const macroCount = document.getElementById('macro-count');
        const microCount = document.getElementById('micro-count');
        const animationCount = document.getElementById('animation-count');
        const stackSize = document.getElementById('stack-size');
        const heapSize = document.getElementById('heap-size');
        const executedTasks = document.getElementById('executed-tasks');
        const queuedTasks = document.getElementById('queued-tasks');
        const renderCount = document.getElementById('render-count');
        const heapObjects = document.getElementById('heap-objects');
        
        // 事件循环步骤
        const loopStep1 = document.getElementById('loop-step-1');
        const loopStep2 = document.getElementById('loop-step-2');
        const loopStep3 = document.getElementById('loop-step-3');
        const loopStep4 = document.getElementById('loop-step-4');
        
        // 日志容器
        const logContainer = document.getElementById('log-container');
        
        // 控制台输出
        const consoleOutput = document.getElementById('console-output');
        
        // 代码输入
        const codeInput = document.getElementById('code-input');
        
        // 控制变量
        let taskId = 1;
        let executedCount = 0;
        let renderCountValue = 0;
        let executionSpeed = 5;
        let isExecuting = false;
        let currentTask = null;
        let progressInterval = null;
        let heapId = 1;
        let stackFrames = [];
        let heapObjectsList = [];
        
        // 速度映射
        const speedMap = {
            1: { name: "非常慢", delay: 2000 },
            2: { name: "很慢", delay: 1500 },
            3: { name: "慢", delay: 1000 },
            4: { name: "较慢", delay: 800 },
            5: { name: "中等", delay: 600 },
            6: { name: "较快", delay: 400 },
            7: { name: "快", delay: 300 },
            8: { name: "很快", delay: 200 },
            9: { name: "非常快", delay: 100 },
            10: { name: "极速", delay: 50 }
        };
        
        // 添加任务函数
        document.getElementById('add-microtask').addEventListener('click', () => {
            addTask('micro', `微任务 ${taskId++}`, 'Promise.then()');
        });
        
        document.getElementById('add-macrotask').addEventListener('click', () => {
            addTask('macro', `宏任务 ${taskId++}`, 'setTimeout()');
        });
        
        document.getElementById('add-animation').addEventListener('click', () => {
            addTask('animation', `动画任务 ${taskId++}`, 'requestAnimationFrame()');
        });
        
        document.getElementById('start-execution').addEventListener('click', () => {
            if (!isExecuting) {
                isExecuting = true;
                executeEventLoop();
            }
        });
        
        document.getElementById('pause-execution').addEventListener('click', () => {
            isExecuting = false;
            if (currentTask) {
                currentTask.classList.remove('executing');
                currentTask = null;
            }
            if (progressInterval) {
                clearInterval(progressInterval);
                progressInterval = null;
            }
            resetLoopSteps();
            addLog('执行已暂停', 'system');
        });
        
        document.getElementById('reset-all').addEventListener('click', () => {
            resetSimulation();
        });
        
        // 代码解析
        document.getElementById('parse-code').addEventListener('click', () => {
            parseAndSimulateCode(codeInput.value);
        });
        
        // 加载示例代码
        document.getElementById('load-example').addEventListener('click', () => {
            codeInput.value = `// 示例代码
console.log('脚本开始');

setTimeout(() => {
    console.log('setTimeout回调');
}, 0);

Promise.resolve().then(() => {
    console.log('Promise.then回调');
});

requestAnimationFrame(() => {
    console.log('requestAnimationFrame回调');
});

let user = { name: '张三', age: 30 };
let data = [1, 2, 3, 4, 5];

console.log('脚本结束');`;
        });
        
        // 速度控制
        document.getElementById('execution-speed').addEventListener('input', (e) => {
            executionSpeed = parseInt(e.target.value);
            document.getElementById('speed-value').textContent = speedMap[executionSpeed].name;
        });
        
        // 解析并模拟代码
        function parseAndSimulateCode(code) {
            resetSimulation();
            
            // 清空队列,但保留初始宏任务
            macroQueue.innerHTML = '<div class="task macro"><span class="task-icon">⏰</span><span>初始脚本执行</span><div class="task-progress"></div></div>';
            microQueue.innerHTML = '';
            animationQueue.innerHTML = '';
            
            // 重置任务ID
            taskId = 1;
            
            // 添加日志
            addLog('开始解析自定义代码', 'system');
            
            // 清空控制台输出
            consoleOutput.innerHTML = '<div class="console-line log">解析代码中...</div>';
            
            // 简单的代码解析逻辑
            const lines = code.split('\n');
            
            for (let i = 0; i < lines.length; i++) {
                const line = lines[i].trim();
                
                // 跳过空行和注释
                if (!line || line.startsWith('//')) continue;
                
                // 检测setTimeout
                if (line.includes('setTimeout')) {
                    addTask('macro', `宏任务 ${taskId++}`, 'setTimeout回调');
                    addLog(`检测到setTimeout: ${line}`, 'macro');
                    addConsoleOutput('log', '检测到setTimeout,已添加到宏任务队列');
                }
                
                // 检测setInterval
                if (line.includes('setInterval')) {
                    addTask('macro', `宏任务 ${taskId++}`, 'setInterval回调');
                    addLog(`检测到setInterval: ${line}`, 'macro');
                    addConsoleOutput('log', '检测到setInterval,已添加到宏任务队列');
                }
                
                // 检测Promise.then
                if (line.includes('.then(') || line.includes('.catch(') || line.includes('.finally(')) {
                    addTask('micro', `微任务 ${taskId++}`, 'Promise回调');
                    addLog(`检测到Promise回调: ${line}`, 'micro');
                    addConsoleOutput('log', '检测到Promise回调,已添加到微任务队列');
                }
                
                // 检测requestAnimationFrame
                if (line.includes('requestAnimationFrame')) {
                    addTask('animation', `动画任务 ${taskId++}`, 'requestAnimationFrame回调');
                    addLog(`检测到requestAnimationFrame: ${line}`, 'animation');
                    addConsoleOutput('log', '检测到requestAnimationFrame,已添加到动画任务队列');
                }
                
                // 检测变量声明
                if (line.includes('let ') || line.includes('const ') || line.includes('var ')) {
                    const varName = extractVariableName(line);
                    if (varName) {
                        // 检测对象或数组
                        if (line.includes('{') || line.includes('[')) {
                            const objectType = line.includes('{') ? 'Object' : 'Array';
                            addHeapObject(objectType, varName, true);
                            addLog(`检测到${objectType}声明: ${varName}`, 'memory');
                            addConsoleOutput('log', `检测到${objectType}声明: ${varName}`);
                        }
                    }
                }
                
                // 检测函数调用
                if (line.includes('(') && line.includes(')') && 
                    !line.includes('function') && 
                    !line.includes('=>') && 
                    !line.includes('setTimeout') && 
                    !line.includes('setInterval') && 
                    !line.includes('requestAnimationFrame')) {
                    const funcName = extractFunctionName(line);
                    if (funcName && funcName !== 'console.log') {
                        addLog(`检测到函数调用: ${funcName}`, 'system');
                        addConsoleOutput('log', `检测到函数调用: ${funcName}`);
                    }
                }
                
                // 检测console.log
                if (line.includes('console.log')) {
                    const message = extractConsoleMessage(line);
                    if (message) {
                        addConsoleOutput('log', message);
                    }
                }
            }
            
            addLog('代码解析完成', 'system');
            addConsoleOutput('log', '代码解析完成,准备执行');
            updateQueueCounts();
        }
        
        // 提取变量名
        function extractVariableName(line) {
            const match = line.match(/(let|const|var)\s+(\w+)/);
            return match ? match[2] : null;
        }
        
        // 提取函数名
        function extractFunctionName(line) {
            const match = line.match(/(\w+)\(/);
            return match ? match[1] : null;
        }
        
        // 提取console.log消息
        function extractConsoleMessage(line) {
            const match = line.match(/console\.log\((['"`])(.*?)\1\)/);
            return match ? match[2] : null;
        }
        
        // 添加任务到队列
        function addTask(type, name, description) {
            const taskElement = document.createElement('div');
            taskElement.className = `task ${type}`;
            taskElement.innerHTML = `
                <span class="task-icon">${getTaskIcon(type)}</span>
                <span>${description || name}</span>
                <div class="task-progress"></div>
            `;
            
            switch(type) {
                case 'macro':
                    macroQueue.appendChild(taskElement);
                    break;
                case 'micro':
                    microQueue.appendChild(taskElement);
                    break;
                case 'animation':
                    animationQueue.appendChild(taskElement);
                    break;
            }
            
            updateQueueCounts();
            addLog(`已添加${getTaskTypeName(type)}: ${description || name}`, type);
        }
        
        // 获取任务图标
        function getTaskIcon(type) {
            switch(type) {
                case 'macro': return '⏰';
                case 'micro': return '⚡';
                case 'animation': return '🎬';
                default: return '📝';
            }
        }
        
        // 获取任务类型名称
        function getTaskTypeName(type) {
            switch(type) {
                case 'macro': return '宏任务';
                case 'micro': return '微任务';
                case 'animation': return '动画任务';
                default: return '任务';
            }
        }
        
        // 更新队列计数
        function updateQueueCounts() {
            macroCount.textContent = macroQueue.children.length;
            microCount.textContent = microQueue.children.length;
            animationCount.textContent = animationQueue.children.length;
            
            const totalQueued = macroQueue.children.length + microQueue.children.length + animationQueue.children.length;
            queuedTasks.textContent = totalQueued;
        }
        
        // 添加控制台输出
        function addConsoleOutput(type, message) {
            const now = new Date();
            const timeString = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}`;
            
            const outputLine = document.createElement('div');
            outputLine.className = `console-line ${type}`;
            outputLine.innerHTML = `<span class="console-time">${timeString}</span> ${message}`;
            
            consoleOutput.appendChild(outputLine);
            consoleOutput.scrollTop = consoleOutput.scrollHeight;
        }
        
        // 添加栈帧
        function pushStackFrame(name, variables) {
            const frameId = `frame-${Date.now()}`;
            const frame = {
                id: frameId,
                name: name,
                variables: variables || []
            };
            
            stackFrames.push(frame);
            
            const frameElement = document.createElement('div');
            frameElement.className = 'stack-frame';
            frameElement.id = frameId;
            frameElement.innerHTML = `
                <strong>${name}</strong>
                <div>变量: ${variables ? variables.join(', ') : '无'}</div>
            `;
            
            // 取消之前活跃的栈帧
            const activeFrames = callStack.querySelectorAll('.stack-frame.active');
            activeFrames.forEach(frame => frame.classList.remove('active'));
            
            // 添加新栈帧并标记为活跃
            callStack.appendChild(frameElement);
            frameElement.classList.add('active');
            
            stackSize.textContent = stackFrames.length;
            
            return frameId;
        }
        
        // 移除栈帧
        function popStackFrame(frameId) {
            const frameIndex = stackFrames.findIndex(frame => frame.id === frameId);
            if (frameIndex !== -1) {
                stackFrames.splice(frameIndex, 1);
            }
            
            const frameElement = document.getElementById(frameId);
            if (frameElement) {
                frameElement.remove();
            }
            
            // 激活上一个栈帧
            if (stackFrames.length > 0) {
                const lastFrameId = stackFrames[stackFrames.length - 1].id;
                const lastFrameElement = document.getElementById(lastFrameId);
                if (lastFrameElement) {
                    lastFrameElement.classList.add('active');
                }
            }
            
            stackSize.textContent = stackFrames.length;
        }
        
        // 添加堆对象
        function addHeapObject(type, value, referenced = true) {
            const objectId = `heap-${heapId++}`;
            const object = {
                id: objectId,
                type: type,
                value: value,
                referenced: referenced
            };
            
            heapObjectsList.push(object);
            
            const objectElement = document.createElement('div');
            objectElement.className = `heap-object ${referenced ? 'referenced' : 'garbage'}`;
            objectElement.id = objectId;
            objectElement.innerHTML = `
                <div><strong>${type}</strong></div>
                <div>${value}</div>
            `;
            
            heapMemory.appendChild(objectElement);
            
            heapSize.textContent = heapObjectsList.length;
            heapObjects.textContent = heapObjectsList.length;
            
            return objectId;
        }
        
        // 标记堆对象为垃圾
        function markHeapObjectAsGarbage(objectId) {
            const object = heapObjectsList.find(obj => obj.id === objectId);
            if (object) {
                object.referenced = false;
                
                const objectElement = document.getElementById(objectId);
                if (objectElement) {
                    objectElement.classList.remove('referenced');
                    objectElement.classList.add('garbage');
                }
            }
        }
        
        // 执行垃圾回收
        function runGarbageCollection() {
            const garbageObjects = heapObjectsList.filter(obj => !obj.referenced);
            
            garbageObjects.forEach(obj => {
                const objectElement = document.getElementById(obj.id);
                if (objectElement) {
                    objectElement.remove();
                }
                
                const objectIndex = heapObjectsList.findIndex(o => o.id === obj.id);
                if (objectIndex !== -1) {
                    heapObjectsList.splice(objectIndex, 1);
                }
            });
            
            heapSize.textContent = heapObjectsList.length;
            heapObjects.textContent = heapObjectsList.length;
            
            if (garbageObjects.length > 0) {
                addLog(`垃圾回收: 释放了 ${garbageObjects.length} 个对象`, 'memory');
                addConsoleOutput('log', `垃圾回收: 释放了 ${garbageObjects.length} 个对象`);
            }
        }
        
        // 模拟事件循环
        async function executeEventLoop() {
            if (!isExecuting) return;
            
            // 执行宏任务
            if (macroQueue.children.length > 0) {
                await executeTask('macro', macroQueue);
                if (!isExecuting) return;
            }
            
            // 执行微任务
            while (microQueue.children.length > 0 && isExecuting) {
                await executeTask('micro', microQueue);
                if (!isExecuting) return;
            }
            
            // 执行动画任务
            if (animationQueue.children.length > 0 && isExecuting) {
                await executeTask('animation', animationQueue);
                if (!isExecuting) return;
            }
            
            // 渲染
            if (isExecuting) {
                await executeRender();
            }
            
            // 垃圾回收
            if (Math.random() > 0.7) { // 随机触发垃圾回收
                runGarbageCollection();
            }
            
            // 如果还有任务,继续执行
            if ((macroQueue.children.length > 0 || microQueue.children.length > 0 || animationQueue.children.length > 0) && isExecuting) {
                setTimeout(executeEventLoop, 100);
            } else {
                isExecuting = false;
                addLog('所有任务执行完成', 'system');
                addConsoleOutput('log', '所有任务执行完成');
            }
        }
        
        // 执行单个任务
        async function executeTask(type, queue) {
            const task = queue.children[0];
            if (!task) return;
            
            currentTask = task;
            task.classList.add('executing');
            
            // 高亮对应的事件循环步骤
            highlightLoopStep(type);
            
            // 添加执行日志
            const taskDescription = task.textContent.trim();
            addLog(`开始执行: ${taskDescription}`, type);
            addConsoleOutput('log', `开始执行: ${taskDescription}`);
            
            // 模拟函数调用 - 添加栈帧
            const frameId = pushStackFrame(
                taskDescription,
                ['局部变量1', '局部变量2']
            );
            
            // 模拟堆分配 - 随机创建一些对象
            if (Math.random() > 0.5) {
                const objectTypes = ['Object', 'Array', 'Function', 'String'];
                const objectType = objectTypes[Math.floor(Math.random() * objectTypes.length)];
                const objectValue = generateRandomValue(objectType);
                
                addHeapObject(objectType, objectValue, true);
                addLog(`堆分配: 创建了 ${objectType} 对象`, 'memory');
                addConsoleOutput('log', `堆分配: 创建了 ${objectType} 对象`);
            }
            
            // 开始进度条动画
            const progressBar = task.querySelector('.task-progress');
            let progress = 0;
            
            progressInterval = setInterval(() => {
                progress += 2;
                progressBar.style.width = `${progress}%`;
                
                if (progress >= 100) {
                    clearInterval(progressInterval);
                    progressInterval = null;
                }
            }, speedMap[executionSpeed].delay / 50);
            
            // 等待任务执行完成
            await delay(speedMap[executionSpeed].delay);
            
            if (progressInterval) {
                clearInterval(progressInterval);
                progressInterval = null;
            }
            
            // 模拟函数返回 - 移除栈帧
            popStackFrame(frameId);
            
            // 随机标记一些对象为垃圾
            if (heapObjectsList.length > 0 && Math.random() > 0.7) {
                const randomIndex = Math.floor(Math.random() * heapObjectsList.length);
                const randomObject = heapObjectsList[randomIndex];
                if (randomObject && randomObject.referenced) {
                    markHeapObjectAsGarbage(randomObject.id);
                    addLog(`对象 ${randomObject.type} 不再被引用`, 'memory');
                    addConsoleOutput('log', `对象 ${randomObject.type} 不再被引用`);
                }
            }
            
            task.classList.remove('executing');
            task.classList.add('completed');
            
            // 短暂显示完成状态后移除
            await delay(300);
            task.remove();
            
            // 更新计数
            executedCount++;
            executedTasks.textContent = executedCount;
            updateQueueCounts();
            
            currentTask = null;
            addLog(`完成执行: ${taskDescription}`, type);
            addConsoleOutput('log', `完成执行: ${taskDescription}`);
        }
        
        // 执行渲染
        async function executeRender() {
            highlightLoopStep('render');
            addLog('开始页面渲染', 'render');
            addConsoleOutput('log', '开始页面渲染');
            
            renderBox.classList.add('rendering');
            renderCountValue++;
            renderCount.textContent = renderCountValue;
            
            await delay(speedMap[executionSpeed].delay);
            
            renderBox.classList.remove('rendering');
            addLog('页面渲染完成', 'render');
            addConsoleOutput('log', '页面渲染完成');
        }
        
        // 高亮事件循环步骤
        function highlightLoopStep(type) {
            resetLoopSteps();
            
            switch(type) {
                case 'macro':
                    loopStep1.classList.add('active');
                    break;
                case 'micro':
                    loopStep2.classList.add('active');
                    break;
                case 'animation':
                    loopStep3.classList.add('active');
                    break;
                case 'render':
                    loopStep4.classList.add('active');
                    break;
            }
        }
        
        // 重置事件循环步骤高亮
        function resetLoopSteps() {
            loopStep1.classList.remove('active');
            loopStep2.classList.remove('active');
            loopStep3.classList.remove('active');
            loopStep4.classList.remove('active');
        }
        
        // 生成随机值
        function generateRandomValue(type) {
            switch(type) {
                case 'Object':
                    return `{key: "value${Math.floor(Math.random() * 100)}"}`;
                case 'Array':
                    return `[${Math.floor(Math.random() * 10)}, ${Math.floor(Math.random() * 10)}]`;
                case 'Function':
                    return `function${Math.floor(Math.random() * 10)}()`;
                case 'String':
                    return `"string${Math.floor(Math.random() * 100)}"`;
                default:
                    return "unknown";
            }
        }
        
        // 重置模拟
        function resetSimulation() {
            isExecuting = false;
            
            if (currentTask) {
                currentTask.classList.remove('executing');
                currentTask = null;
            }
            
            if (progressInterval) {
                clearInterval(progressInterval);
                progressInterval = null;
            }
            
            // 清空队列
            macroQueue.innerHTML = '<div class="task macro"><span class="task-icon">⏰</span><span>初始脚本执行</span><div class="task-progress"></div></div>';
            microQueue.innerHTML = '';
            animationQueue.innerHTML = '';
            
            // 清空内存
            callStack.innerHTML = '<div class="stack-frame active"><strong>全局执行上下文</strong><div>变量: 全局变量</div></div>';
            heapMemory.innerHTML = '';
            
            // 重置内存数据
            stackFrames = [];
            heapObjectsList = [];
            heapId = 1;
            
            // 重置计数
            taskId = 1;
            executedCount = 0;
            renderCountValue = 0;
            executedTasks.textContent = '0';
            renderCount.textContent = '0';
            stackSize.textContent = '1';
            heapSize.textContent = '0';
            heapObjects.textContent = '0';
            
            // 更新队列计数
            updateQueueCounts();
            
            // 重置事件循环步骤
            resetLoopSteps();
            
            // 清空日志
            logContainer.innerHTML = '';
            addLog('模拟器已重置', 'system');
            
            // 清空控制台输出
            consoleOutput.innerHTML = '<div class="console-line log">模拟器已重置</div>';
        }
        
        // 添加日志
        function addLog(message, type) {
            const now = new Date();
            const timeString = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}`;
            
            const logEntry = document.createElement('div');
            logEntry.className = 'log-entry';
            logEntry.innerHTML = `
                <span class="log-time">${timeString}</span>
                <span class="log-message ${type}">${message}</span>
            `;
            
            logContainer.appendChild(logEntry);
            logContainer.scrollTop = logContainer.scrollHeight;
        }
        
        // 延迟函数
        function delay(ms) {
            return new Promise(resolve => setTimeout(resolve, ms));
        }
        
        // 初始化示例任务
        function initializeExampleTasks() {
            addTask('micro', '微任务 1', 'Promise.then()');
            addTask('macro', '宏任务 1', 'setTimeout()');
            addTask('animation', '动画任务 1', 'requestAnimationFrame()');
            addTask('micro', '微任务 2', 'Promise.resolve().then()');
            addTask('macro', '宏任务 2', 'setInterval()');
            
            // 初始化一些堆对象
            addHeapObject('Object', '{name: "user", age: 30}');
            addHeapObject('Array', '[1, 2, 3, 4, 5]');
            addHeapObject('Function', 'function clickHandler()');
        }
        
        // 页面加载后初始化
        window.addEventListener('load', () => {
            initializeExampleTasks();
            addLog('模拟器已初始化,准备执行任务', 'system');
            addConsoleOutput('log', '模拟器已初始化,准备执行任务');
        });
    </script>
</body>
</html>
相关推荐
xier1234563 小时前
高性能和高灵活度的react表格组件
前端
曦曜2923 小时前
富文本编辑器
javascript
你打不到我呢3 小时前
nestjs入门:上手数据库与prisma
前端
多啦C梦a3 小时前
React 实战:从 setInterval 到 useInterval,一次搞懂定时器 Hook(还能暂停!)
前端·javascript·react.js
闲不住的李先森3 小时前
乐观更新
前端·react.js·设计模式
笔尖的记忆4 小时前
【前端架构和框架】react组件化&数据流
前端·面试
zhangzelin8884 小时前
TypeScript入门指南:JavaScript的类型化超集
前端·javascript·其他·typescript
lichenyang4534 小时前
流式聊天界面实现解析:从零到一构建实时对话体验
前端
天蓝色的鱼鱼4 小时前
Turbopack vs Webpack vs Vite:前端构建工具三分天下,谁将胜出?
前端·webpack