Skip to content

9.4 HTML5 Web Workers API

关键字

Worker, postMessage, onmessage, onerror, terminate, importScripts, SharedWorker, ServiceWorker, MessagePort, transferable objects

学习目标

  • 理解Web Workers的基本概念和工作原理
  • 掌握主线程与Worker线程之间的通信机制
  • 学会使用Web Workers进行性能优化
  • 了解不同类型的Web Workers及其应用场景
  • 能够构建实际的Web Workers应用

9.4.1 Web Workers基础概念

什么是Web Workers

Web Workers是HTML5提供的一种在后台运行JavaScript的机制,允许创建独立的线程来执行计算密集型任务,而不会阻塞用户界面的响应。

Web Workers的优势

  1. 多线程处理:避免阻塞主线程
  2. 性能提升:利用多核CPU进行并行计算
  3. 用户体验:保持界面响应性
  4. 任务隔离:独立的执行环境

基本Web Workers HTML结构

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Web Workers基础</title>
</head>
<body>
    <h1>Web Workers基础示例</h1>
    
    <!-- 控制面板 -->
    <section class="control-panel">
        <h2>控制面板</h2>
        <button id="start-worker">启动Worker</button>
        <button id="stop-worker">停止Worker</button>
        <button id="send-message">发送消息</button>
        <input type="text" id="message-input" placeholder="输入要发送的消息">
    </section>
    
    <!-- 状态显示 -->
    <section class="status-display">
        <h2>Worker状态</h2>
        <div id="worker-status" role="status" aria-live="polite">
            未启动
        </div>
    </section>
    
    <!-- 消息日志 -->
    <section class="message-log">
        <h2>消息日志</h2>
        <div id="message-log" role="log" aria-live="polite"></div>
    </section>
    
    <!-- 性能监控 -->
    <section class="performance-monitor">
        <h2>性能监控</h2>
        <div id="performance-info">
            <p>主线程状态: <span id="main-thread-status">空闲</span></p>
            <p>Worker线程状态: <span id="worker-thread-status">未启动</span></p>
        </div>
    </section>
    
    <script>
        // Web Workers基础实现
        document.addEventListener('DOMContentLoaded', function() {
            const startButton = document.getElementById('start-worker');
            const stopButton = document.getElementById('stop-worker');
            const sendButton = document.getElementById('send-message');
            const messageInput = document.getElementById('message-input');
            const workerStatus = document.getElementById('worker-status');
            const messageLog = document.getElementById('message-log');
            const mainThreadStatus = document.getElementById('main-thread-status');
            const workerThreadStatus = document.getElementById('worker-thread-status');
            
            let worker = null;
            
            // 启动Worker
            startButton.addEventListener('click', function() {
                if (!worker) {
                    // 创建Worker实例
                    worker = new Worker('worker.js');
                    
                    // 监听Worker消息
                    worker.onmessage = function(e) {
                        handleWorkerMessage(e.data);
                    };
                    
                    // 监听Worker错误
                    worker.onerror = function(e) {
                        handleWorkerError(e);
                    };
                    
                    updateStatus('Worker已启动');
                    workerThreadStatus.textContent = '运行中';
                }
            });
            
            // 停止Worker
            stopButton.addEventListener('click', function() {
                if (worker) {
                    worker.terminate();
                    worker = null;
                    updateStatus('Worker已停止');
                    workerThreadStatus.textContent = '已停止';
                }
            });
            
            // 发送消息
            sendButton.addEventListener('click', function() {
                if (worker && messageInput.value.trim()) {
                    const message = messageInput.value.trim();
                    worker.postMessage(message);
                    logMessage('发送到Worker: ' + message);
                    messageInput.value = '';
                }
            });
            
            // 处理Worker消息
            function handleWorkerMessage(data) {
                logMessage('收到Worker消息: ' + data);
            }
            
            // 处理Worker错误
            function handleWorkerError(error) {
                logMessage('Worker错误: ' + error.message);
            }
            
            // 更新状态
            function updateStatus(status) {
                workerStatus.textContent = status;
            }
            
            // 记录消息
            function logMessage(message) {
                const logEntry = document.createElement('div');
                logEntry.textContent = new Date().toLocaleTimeString() + ': ' + message;
                messageLog.appendChild(logEntry);
                messageLog.scrollTop = messageLog.scrollHeight;
            }
        });
    </script>
</body>
</html>

Web Workers类型

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Web Workers类型</title>
</head>
<body>
    <h1>Web Workers类型示例</h1>
    
    <!-- Dedicated Worker -->
    <section class="dedicated-worker">
        <h2>Dedicated Worker</h2>
        <p>专用Worker,只能被创建它的脚本访问</p>
        <button id="create-dedicated">创建Dedicated Worker</button>
        <div id="dedicated-result" role="region" aria-live="polite"></div>
    </section>
    
    <!-- Shared Worker -->
    <section class="shared-worker">
        <h2>Shared Worker</h2>
        <p>共享Worker,可以被多个脚本访问</p>
        <button id="create-shared">创建Shared Worker</button>
        <div id="shared-result" role="region" aria-live="polite"></div>
    </section>
    
    <!-- Service Worker -->
    <section class="service-worker">
        <h2>Service Worker</h2>
        <p>服务Worker,用于网络代理和缓存</p>
        <button id="register-service">注册Service Worker</button>
        <div id="service-result" role="region" aria-live="polite"></div>
    </section>
    
    <script>
        // Web Workers类型实现
        document.addEventListener('DOMContentLoaded', function() {
            // Dedicated Worker
            document.getElementById('create-dedicated').addEventListener('click', function() {
                const dedicatedResult = document.getElementById('dedicated-result');
                
                try {
                    const worker = new Worker('dedicated-worker.js');
                    
                    worker.postMessage('Hello from main thread');
                    
                    worker.onmessage = function(e) {
                        dedicatedResult.innerHTML = `
                            <h3>Dedicated Worker响应</h3>
                            <p>消息: ${e.data}</p>
                            <p>时间: ${new Date().toLocaleString()}</p>
                        `;
                    };
                    
                    worker.onerror = function(e) {
                        dedicatedResult.innerHTML = `
                            <h3>错误</h3>
                            <p>错误信息: ${e.message}</p>
                        `;
                    };
                } catch (error) {
                    dedicatedResult.innerHTML = `
                        <h3>创建失败</h3>
                        <p>错误: ${error.message}</p>
                    `;
                }
            });
            
            // Shared Worker
            document.getElementById('create-shared').addEventListener('click', function() {
                const sharedResult = document.getElementById('shared-result');
                
                try {
                    const worker = new SharedWorker('shared-worker.js');
                    const port = worker.port;
                    
                    port.start();
                    
                    port.postMessage('Hello from main thread');
                    
                    port.onmessage = function(e) {
                        sharedResult.innerHTML = `
                            <h3>Shared Worker响应</h3>
                            <p>消息: ${e.data}</p>
                            <p>时间: ${new Date().toLocaleString()}</p>
                        `;
                    };
                    
                    port.onerror = function(e) {
                        sharedResult.innerHTML = `
                            <h3>错误</h3>
                            <p>错误信息: ${e.message}</p>
                        `;
                    };
                } catch (error) {
                    sharedResult.innerHTML = `
                        <h3>创建失败</h3>
                        <p>错误: ${error.message}</p>
                    `;
                }
            });
            
            // Service Worker
            document.getElementById('register-service').addEventListener('click', function() {
                const serviceResult = document.getElementById('service-result');
                
                if ('serviceWorker' in navigator) {
                    navigator.serviceWorker.register('service-worker.js')
                        .then(function(registration) {
                            serviceResult.innerHTML = `
                                <h3>Service Worker注册成功</h3>
                                <p>作用域: ${registration.scope}</p>
                                <p>状态: ${registration.active ? '活动' : '未活动'}</p>
                            `;
                        })
                        .catch(function(error) {
                            serviceResult.innerHTML = `
                                <h3>注册失败</h3>
                                <p>错误: ${error.message}</p>
                            `;
                        });
                } else {
                    serviceResult.innerHTML = `
                        <h3>不支持</h3>
                        <p>浏览器不支持Service Worker</p>
                    `;
                }
            });
        });
    </script>
</body>
</html>

9.4.2 主线程与Worker通信

消息传递机制

Web Workers通过消息传递机制与主线程通信,使用postMessage发送消息,onmessage接收消息。

基本通信HTML结构

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Worker通信机制</title>
</head>
<body>
    <h1>Worker通信机制示例</h1>
    
    <!-- 数据输入区 -->
    <section class="data-input">
        <h2>数据输入</h2>
        <div class="input-group">
            <label for="number-input">数字 (用于计算):</label>
            <input type="number" id="number-input" value="1000000" min="1">
        </div>
        <div class="input-group">
            <label for="text-input">文本 (用于处理):</label>
            <textarea id="text-input" placeholder="输入要处理的文本"></textarea>
        </div>
        <div class="input-group">
            <label for="json-input">JSON数据:</label>
            <textarea id="json-input" placeholder='{"key": "value"}'></textarea>
        </div>
    </section>
    
    <!-- 操作按钮 -->
    <section class="operations">
        <h2>操作</h2>
        <button id="calculate-fibonacci">计算斐波那契数列</button>
        <button id="process-text">处理文本</button>
        <button id="process-json">处理JSON</button>
        <button id="send-array">发送数组</button>
        <button id="transfer-buffer">传输ArrayBuffer</button>
    </section>
    
    <!-- 结果显示 -->
    <section class="results">
        <h2>处理结果</h2>
        <div id="result-display" role="region" aria-live="polite"></div>
    </section>
    
    <!-- 性能监控 -->
    <section class="performance">
        <h2>性能监控</h2>
        <div id="performance-display">
            <p>处理时间: <span id="processing-time">-</span></p>
            <p>数据大小: <span id="data-size">-</span></p>
            <p>传输方式: <span id="transfer-method">-</span></p>
        </div>
    </section>
    
    <script>
        // Worker通信机制实现
        document.addEventListener('DOMContentLoaded', function() {
            const numberInput = document.getElementById('number-input');
            const textInput = document.getElementById('text-input');
            const jsonInput = document.getElementById('json-input');
            const resultDisplay = document.getElementById('result-display');
            const processingTime = document.getElementById('processing-time');
            const dataSize = document.getElementById('data-size');
            const transferMethod = document.getElementById('transfer-method');
            
            let worker = null;
            let startTime = 0;
            
            // 创建Worker
            function createWorker() {
                if (!worker) {
                    worker = new Worker('communication-worker.js');
                    
                    worker.onmessage = function(e) {
                        const endTime = performance.now();
                        const duration = endTime - startTime;
                        
                        handleWorkerResponse(e.data, duration);
                    };
                    
                    worker.onerror = function(e) {
                        displayError('Worker错误: ' + e.message);
                    };
                }
                return worker;
            }
            
            // 计算斐波那契数列
            document.getElementById('calculate-fibonacci').addEventListener('click', function() {
                const n = parseInt(numberInput.value);
                if (isNaN(n) || n <= 0) {
                    displayError('请输入有效的正整数');
                    return;
                }
                
                const currentWorker = createWorker();
                startTime = performance.now();
                
                currentWorker.postMessage({
                    type: 'fibonacci',
                    data: n
                });
                
                updatePerformanceInfo(JSON.stringify({type: 'fibonacci', data: n}), 'postMessage');
                displayMessage('正在计算斐波那契数列...');
            });
            
            // 处理文本
            document.getElementById('process-text').addEventListener('click', function() {
                const text = textInput.value.trim();
                if (!text) {
                    displayError('请输入要处理的文本');
                    return;
                }
                
                const currentWorker = createWorker();
                startTime = performance.now();
                
                currentWorker.postMessage({
                    type: 'processText',
                    data: text
                });
                
                updatePerformanceInfo(text, 'postMessage');
                displayMessage('正在处理文本...');
            });
            
            // 处理JSON
            document.getElementById('process-json').addEventListener('click', function() {
                const jsonText = jsonInput.value.trim();
                if (!jsonText) {
                    displayError('请输入JSON数据');
                    return;
                }
                
                try {
                    const jsonData = JSON.parse(jsonText);
                    const currentWorker = createWorker();
                    startTime = performance.now();
                    
                    currentWorker.postMessage({
                        type: 'processJson',
                        data: jsonData
                    });
                    
                    updatePerformanceInfo(jsonText, 'postMessage');
                    displayMessage('正在处理JSON数据...');
                } catch (error) {
                    displayError('JSON格式错误: ' + error.message);
                }
            });
            
            // 发送数组
            document.getElementById('send-array').addEventListener('click', function() {
                const arraySize = parseInt(numberInput.value);
                const largeArray = new Array(arraySize).fill(0).map((_, i) => i);
                
                const currentWorker = createWorker();
                startTime = performance.now();
                
                currentWorker.postMessage({
                    type: 'processArray',
                    data: largeArray
                });
                
                updatePerformanceInfo(`数组(${arraySize}个元素)`, 'postMessage (复制)');
                displayMessage('正在处理数组...');
            });
            
            // 传输ArrayBuffer
            document.getElementById('transfer-buffer').addEventListener('click', function() {
                const bufferSize = parseInt(numberInput.value);
                const buffer = new ArrayBuffer(bufferSize * 4);
                const view = new Int32Array(buffer);
                
                // 填充数据
                for (let i = 0; i < bufferSize; i++) {
                    view[i] = i;
                }
                
                const currentWorker = createWorker();
                startTime = performance.now();
                
                // 使用Transferable Objects传输
                currentWorker.postMessage({
                    type: 'processBuffer',
                    data: buffer
                }, [buffer]);
                
                updatePerformanceInfo(`ArrayBuffer(${bufferSize * 4}字节)`, 'postMessage (传输)');
                displayMessage('正在传输ArrayBuffer...');
            });
            
            // 处理Worker响应
            function handleWorkerResponse(data, duration) {
                processingTime.textContent = duration.toFixed(2) + 'ms';
                
                if (data.error) {
                    displayError(data.error);
                } else {
                    displayResult(data);
                }
            }
            
            // 显示结果
            function displayResult(data) {
                let resultHtml = '<h3>处理结果</h3>';
                
                switch (data.type) {
                    case 'fibonacci':
                        resultHtml += `
                            <p>斐波那契数列第${data.input}项: ${data.result}</p>
                            <p>计算步骤: ${data.steps || '未知'}</p>
                        `;
                        break;
                    case 'processText':
                        resultHtml += `
                            <p>原文本长度: ${data.originalLength}</p>
                            <p>处理后长度: ${data.processedLength}</p>
                            <p>单词数: ${data.wordCount}</p>
                            <p>字符统计: ${JSON.stringify(data.charCount)}</p>
                        `;
                        break;
                    case 'processJson':
                        resultHtml += `
                            <p>JSON对象属性数: ${data.propertyCount}</p>
                            <p>处理后的数据: ${JSON.stringify(data.result)}</p>
                        `;
                        break;
                    case 'processArray':
                        resultHtml += `
                            <p>数组长度: ${data.length}</p>
                            <p>总和: ${data.sum}</p>
                            <p>平均值: ${data.average}</p>
                            <p>最大值: ${data.max}</p>
                            <p>最小值: ${data.min}</p>
                        `;
                        break;
                    case 'processBuffer':
                        resultHtml += `
                            <p>缓冲区大小: ${data.bufferSize}字节</p>
                            <p>元素数量: ${data.elementCount}</p>
                            <p>处理结果: ${data.result}</p>
                        `;
                        break;
                }
                
                resultDisplay.innerHTML = resultHtml;
            }
            
            // 显示消息
            function displayMessage(message) {
                resultDisplay.innerHTML = `<p>${message}</p>`;
            }
            
            // 显示错误
            function displayError(error) {
                resultDisplay.innerHTML = `<p style="color: red;">错误: ${error}</p>`;
            }
            
            // 更新性能信息
            function updatePerformanceInfo(data, method) {
                const size = new Blob([JSON.stringify(data)]).size;
                dataSize.textContent = size + ' bytes';
                transferMethod.textContent = method;
            }
        });
    </script>
</body>
</html>

复杂数据传输示例

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>
</head>
<body>
    <h1>复杂数据传输示例</h1>
    
    <!-- 数据类型选择 -->
    <section class="data-types">
        <h2>数据类型</h2>
        <div class="type-selector">
            <button id="send-object">发送对象</button>
            <button id="send-function">发送函数字符串</button>
            <button id="send-date">发送日期</button>
            <button id="send-regexp">发送正则表达式</button>
            <button id="send-file">发送文件数据</button>
        </div>
    </section>
    
    <!-- 文件输入 -->
    <section class="file-input">
        <h2>文件输入</h2>
        <input type="file" id="file-input" accept="*/*">
    </section>
    
    <!-- 传输选项 -->
    <section class="transfer-options">
        <h2>传输选项</h2>
        <div class="options">
            <label>
                <input type="radio" name="transfer-type" value="copy" checked>
                复制传输(默认)
            </label>
            <label>
                <input type="radio" name="transfer-type" value="transfer">
                转移传输(Transferable Objects)
            </label>
        </div>
    </section>
    
    <!-- 结果显示 -->
    <section class="results">
        <h2>传输结果</h2>
        <div id="transfer-results" role="region" aria-live="polite"></div>
    </section>
    
    <script>
        // 复杂数据传输实现
        document.addEventListener('DOMContentLoaded', function() {
            const fileInput = document.getElementById('file-input');
            const transferResults = document.getElementById('transfer-results');
            
            let worker = null;
            
            // 创建Worker
            function createWorker() {
                if (!worker) {
                    worker = new Worker('data-transfer-worker.js');
                    
                    worker.onmessage = function(e) {
                        handleWorkerMessage(e.data);
                    };
                    
                    worker.onerror = function(e) {
                        displayError('Worker错误: ' + e.message);
                    };
                }
                return worker;
            }
            
            // 发送对象
            document.getElementById('send-object').addEventListener('click', function() {
                const complexObject = {
                    id: Date.now(),
                    name: '复杂对象',
                    data: {
                        numbers: [1, 2, 3, 4, 5],
                        nested: {
                            deep: {
                                value: 'nested value'
                            }
                        }
                    },
                    metadata: {
                        created: new Date().toISOString(),
                        version: '1.0.0'
                    }
                };
                
                sendToWorker('object', complexObject);
            });
            
            // 发送函数字符串
            document.getElementById('send-function').addEventListener('click', function() {
                const functionString = `
                    function calculateSum(arr) {
                        return arr.reduce((sum, num) => sum + num, 0);
                    }
                `;
                
                sendToWorker('function', {
                    code: functionString,
                    args: [1, 2, 3, 4, 5]
                });
            });
            
            // 发送日期
            document.getElementById('send-date').addEventListener('click', function() {
                const dateData = {
                    current: new Date(),
                    formatted: new Date().toISOString(),
                    timestamp: Date.now()
                };
                
                sendToWorker('date', dateData);
            });
            
            // 发送正则表达式
            document.getElementById('send-regexp').addEventListener('click', function() {
                const regexData = {
                    pattern: /\b\w+\b/g,
                    patternString: '\\b\\w+\\b',
                    flags: 'g',
                    testString: 'Hello World! This is a test.'
                };
                
                sendToWorker('regexp', regexData);
            });
            
            // 发送文件数据
            document.getElementById('send-file').addEventListener('click', function() {
                const file = fileInput.files[0];
                if (!file) {
                    displayError('请选择一个文件');
                    return;
                }
                
                const reader = new FileReader();
                reader.onload = function(e) {
                    const fileData = {
                        name: file.name,
                        size: file.size,
                        type: file.type,
                        lastModified: file.lastModified,
                        content: e.target.result
                    };
                    
                    sendToWorker('file', fileData);
                };
                reader.readAsDataURL(file);
            });
            
            // 发送数据到Worker
            function sendToWorker(type, data) {
                const currentWorker = createWorker();
                const transferType = document.querySelector('input[name="transfer-type"]:checked').value;
                
                const message = {
                    type: type,
                    data: data,
                    transferType: transferType,
                    timestamp: Date.now()
                };
                
                displayMessage('正在发送数据...');
                
                if (transferType === 'transfer' && type === 'file' && data.content.startsWith('data:')) {
                    // 对于某些数据类型,尝试使用Transferable Objects
                    try {
                        const buffer = new ArrayBuffer(data.size);
                        currentWorker.postMessage(message, [buffer]);
                    } catch (error) {
                        // 回退到复制传输
                        currentWorker.postMessage(message);
                    }
                } else {
                    currentWorker.postMessage(message);
                }
            }
            
            // 处理Worker消息
            function handleWorkerMessage(data) {
                if (data.error) {
                    displayError(data.error);
                } else {
                    displayResult(data);
                }
            }
            
            // 显示结果
            function displayResult(data) {
                let resultHtml = `
                    <h3>传输成功</h3>
                    <p>数据类型: ${data.type}</p>
                    <p>处理时间: ${data.processingTime}ms</p>
                    <p>数据大小: ${data.dataSize} bytes</p>
                `;
                
                switch (data.type) {
                    case 'object':
                        resultHtml += `
                            <h4>对象处理结果</h4>
                            <p>属性数量: ${data.result.propertyCount}</p>
                            <p>嵌套深度: ${data.result.nestingDepth}</p>
                            <p>数组元素: ${data.result.arrayElements}</p>
                        `;
                        break;
                    case 'function':
                        resultHtml += `
                            <h4>函数执行结果</h4>
                            <p>执行结果: ${data.result.executionResult}</p>
                            <p>函数名: ${data.result.functionName}</p>
                        `;
                        break;
                    case 'date':
                        resultHtml += `
                            <h4>日期处理结果</h4>
                            <p>格式化日期: ${data.result.formatted}</p>
                            <p>时间戳: ${data.result.timestamp}</p>
                            <p>时区: ${data.result.timezone}</p>
                        `;
                        break;
                    case 'regexp':
                        resultHtml += `
                            <h4>正则表达式处理结果</h4>
                            <p>匹配结果: ${JSON.stringify(data.result.matches)}</p>
                            <p>匹配数量: ${data.result.matchCount}</p>
                        `;
                        break;
                    case 'file':
                        resultHtml += `
                            <h4>文件处理结果</h4>
                            <p>文件名: ${data.result.fileName}</p>
                            <p>文件大小: ${data.result.fileSize} bytes</p>
                            <p>文件类型: ${data.result.fileType}</p>
                            <p>内容预览: ${data.result.contentPreview}</p>
                        `;
                        break;
                }
                
                transferResults.innerHTML = resultHtml;
            }
            
            // 显示消息
            function displayMessage(message) {
                transferResults.innerHTML = `<p>${message}</p>`;
            }
            
            // 显示错误
            function displayError(error) {
                transferResults.innerHTML = `<p style="color: red;">错误: ${error}</p>`;
            }
        });
    </script>
</body>
</html>

9.4.3 Worker文件管理

Worker文件结构

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Worker文件管理</title>
</head>
<body>
    <h1>Worker文件管理示例</h1>
    
    <!-- 文件结构说明 -->
    <section class="file-structure">
        <h2>推荐的文件结构</h2>
        <pre>
project/
├── index.html
├── js/
│   ├── main.js
│   └── workers/
│       ├── calculation-worker.js
│       ├── data-processing-worker.js
│       └── shared/
│           ├── utils.js
│           └── constants.js
└── data/
    └── sample-data.json
        </pre>
    </section>
    
    <!-- Worker管理界面 -->
    <section class="worker-management">
        <h2>Worker管理</h2>
        <div class="worker-controls">
            <button id="create-calculation-worker">创建计算Worker</button>
            <button id="create-data-worker">创建数据处理Worker</button>
            <button id="import-scripts">导入脚本</button>
            <button id="cleanup-workers">清理Workers</button>
        </div>
        
        <div class="worker-status">
            <h3>Worker状态</h3>
            <div id="worker-status-list" role="list"></div>
        </div>
    </section>
    
    <!-- 脚本导入测试 -->
    <section class="script-import">
        <h2>脚本导入测试</h2>
        <div class="import-controls">
            <input type="url" id="script-url" placeholder="输入脚本URL">
            <button id="import-external">导入外部脚本</button>
        </div>
        <div id="import-results" role="region" aria-live="polite"></div>
    </section>
    
    <!-- 错误处理 -->
    <section class="error-handling">
        <h2>错误处理</h2>
        <div class="error-controls">
            <button id="trigger-error">触发错误</button>
            <button id="test-invalid-worker">测试无效Worker</button>
            <button id="test-network-error">测试网络错误</button>
        </div>
        <div id="error-log" role="log" aria-live="polite"></div>
    </section>
    
    <script>
        // Worker文件管理实现
        document.addEventListener('DOMContentLoaded', function() {
            const workerStatusList = document.getElementById('worker-status-list');
            const importResults = document.getElementById('import-results');
            const errorLog = document.getElementById('error-log');
            const scriptUrl = document.getElementById('script-url');
            
            let workers = new Map();
            let workerIdCounter = 0;
            
            // 创建计算Worker
            document.getElementById('create-calculation-worker').addEventListener('click', function() {
                createWorker('calculation-worker.js', 'calculation');
            });
            
            // 创建数据处理Worker
            document.getElementById('create-data-worker').addEventListener('click', function() {
                createWorker('data-processing-worker.js', 'data-processing');
            });
            
            // 导入脚本
            document.getElementById('import-scripts').addEventListener('click', function() {
                testImportScripts();
            });
            
            // 清理Workers
            document.getElementById('cleanup-workers').addEventListener('click', function() {
                cleanupWorkers();
            });
            
            // 导入外部脚本
            document.getElementById('import-external').addEventListener('click', function() {
                const url = scriptUrl.value.trim();
                if (url) {
                    importExternalScript(url);
                } else {
                    displayError('请输入有效的脚本URL');
                }
            });
            
            // 触发错误
            document.getElementById('trigger-error').addEventListener('click', function() {
                triggerWorkerError();
            });
            
            // 测试无效Worker
            document.getElementById('test-invalid-worker').addEventListener('click', function() {
                testInvalidWorker();
            });
            
            // 测试网络错误
            document.getElementById('test-network-error').addEventListener('click', function() {
                testNetworkError();
            });
            
            // 创建Worker
            function createWorker(scriptPath, type) {
                const workerId = ++workerIdCounter;
                const workerName = `${type}-${workerId}`;
                
                try {
                    const worker = new Worker(scriptPath);
                    
                    worker.onmessage = function(e) {
                        handleWorkerMessage(workerName, e.data);
                    };
                    
                    worker.onerror = function(e) {
                        handleWorkerError(workerName, e);
                    };
                    
                    workers.set(workerName, {
                        worker: worker,
                        type: type,
                        created: new Date(),
                        status: 'active'
                    });
                    
                    updateWorkerStatus();
                    
                    // 发送初始化消息
                    worker.postMessage({
                        type: 'init',
                        workerId: workerId,
                        workerName: workerName
                    });
                    
                } catch (error) {
                    displayError(`创建Worker失败: ${error.message}`);
                }
            }
            
            // 测试脚本导入
            function testImportScripts() {
                const worker = new Worker('import-scripts-worker.js');
                
                worker.onmessage = function(e) {
                    importResults.innerHTML = `
                        <h3>脚本导入结果</h3>
                        <p>状态: ${e.data.status}</p>
                        <p>导入的脚本: ${e.data.scripts.join(', ')}</p>
                        <p>可用函数: ${e.data.availableFunctions.join(', ')}</p>
                    `;
                };
                
                worker.onerror = function(e) {
                    importResults.innerHTML = `
                        <h3>脚本导入失败</h3>
                        <p>错误: ${e.message}</p>
                    `;
                };
                
                worker.postMessage({type: 'importScripts'});
            }
            
            // 导入外部脚本
            function importExternalScript(url) {
                const worker = new Worker('external-import-worker.js');
                
                worker.onmessage = function(e) {
                    if (e.data.success) {
                        importResults.innerHTML = `
                            <h3>外部脚本导入成功</h3>
                            <p>URL: ${url}</p>
                            <p>响应: ${JSON.stringify(e.data.result)}</p>
                        `;
                    } else {
                        importResults.innerHTML = `
                            <h3>外部脚本导入失败</h3>
                            <p>错误: ${e.data.error}</p>
                        `;
                    }
                };
                
                worker.onerror = function(e) {
                    importResults.innerHTML = `
                        <h3>Worker错误</h3>
                        <p>错误: ${e.message}</p>
                    `;
                };
                
                worker.postMessage({
                    type: 'importExternal',
                    url: url
                });
            }
            
            // 清理Workers
            function cleanupWorkers() {
                let terminatedCount = 0;
                
                workers.forEach((workerInfo, name) => {
                    if (workerInfo.status === 'active') {
                        workerInfo.worker.terminate();
                        workerInfo.status = 'terminated';
                        terminatedCount++;
                    }
                });
                
                workers.clear();
                updateWorkerStatus();
                
                displayMessage(`已清理${terminatedCount}个Worker`);
            }
            
            // 触发Worker错误
            function triggerWorkerError() {
                const worker = new Worker('error-worker.js');
                
                worker.onmessage = function(e) {
                    displayMessage('Worker正常响应: ' + e.data);
                };
                
                worker.onerror = function(e) {
                    displayError(`Worker错误: ${e.message} (${e.filename}:${e.lineno})`);
                };
                
                worker.postMessage({type: 'triggerError'});
            }
            
            // 测试无效Worker
            function testInvalidWorker() {
                try {
                    const worker = new Worker('non-existent-worker.js');
                    
                    worker.onerror = function(e) {
                        displayError(`无效Worker错误: ${e.message}`);
                    };
                    
                    worker.postMessage({type: 'test'});
                } catch (error) {
                    displayError(`创建无效Worker失败: ${error.message}`);
                }
            }
            
            // 测试网络错误
            function testNetworkError() {
                try {
                    const worker = new Worker('https://invalid-domain-for-testing.com/worker.js');
                    
                    worker.onerror = function(e) {
                        displayError(`网络错误: ${e.message}`);
                    };
                    
                    worker.postMessage({type: 'test'});
                } catch (error) {
                    displayError(`网络Worker创建失败: ${error.message}`);
                }
            }
            
            // 处理Worker消息
            function handleWorkerMessage(workerName, data) {
                displayMessage(`Worker ${workerName}: ${JSON.stringify(data)}`);
            }
            
            // 处理Worker错误
            function handleWorkerError(workerName, error) {
                displayError(`Worker ${workerName} 错误: ${error.message}`);
                
                // 更新Worker状态
                if (workers.has(workerName)) {
                    workers.get(workerName).status = 'error';
                    updateWorkerStatus();
                }
            }
            
            // 更新Worker状态
            function updateWorkerStatus() {
                let statusHtml = '';
                
                if (workers.size === 0) {
                    statusHtml = '<p>没有活动的Worker</p>';
                } else {
                    workers.forEach((workerInfo, name) => {
                        statusHtml += `
                            <div class="worker-item" role="listitem">
                                <h4>${name}</h4>
                                <p>类型: ${workerInfo.type}</p>
                                <p>状态: ${workerInfo.status}</p>
                                <p>创建时间: ${workerInfo.created.toLocaleString()}</p>
                                <button onclick="terminateWorker('${name}')">终止</button>
                            </div>
                        `;
                    });
                }
                
                workerStatusList.innerHTML = statusHtml;
            }
            
            // 终止Worker
            window.terminateWorker = function(workerName) {
                if (workers.has(workerName)) {
                    const workerInfo = workers.get(workerName);
                    workerInfo.worker.terminate();
                    workerInfo.status = 'terminated';
                    updateWorkerStatus();
                    displayMessage(`Worker ${workerName} 已终止`);
                }
            };
            
            // 显示消息
            function displayMessage(message) {
                const logEntry = document.createElement('div');
                logEntry.textContent = `${new Date().toLocaleTimeString()}: ${message}`;
                errorLog.appendChild(logEntry);
                errorLog.scrollTop = errorLog.scrollHeight;
            }
            
            // 显示错误
            function displayError(error) {
                const logEntry = document.createElement('div');
                logEntry.style.color = 'red';
                logEntry.textContent = `${new Date().toLocaleTimeString()}: ${error}`;
                errorLog.appendChild(logEntry);
                errorLog.scrollTop = errorLog.scrollHeight;
            }
        });
    </script>
</body>
</html>

9.4.4 性能优化应用

数据处理优化

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Web Workers性能优化</title>
</head>
<body>
    <h1>Web Workers性能优化应用</h1>
    
    <!-- 性能测试控制 -->
    <section class="performance-controls">
        <h2>性能测试</h2>
        <div class="test-controls">
            <button id="test-main-thread">主线程处理</button>
            <button id="test-worker-thread">Worker线程处理</button>
            <button id="test-parallel">并行处理</button>
            <button id="test-batch">批处理</button>
        </div>
        
        <div class="test-settings">
            <label>
                数据量:
                <select id="data-size">
                    <option value="1000">1,000</option>
                    <option value="10000">10,000</option>
                    <option value="100000" selected>100,000</option>
                    <option value="1000000">1,000,000</option>
                </select>
            </label>
            <label>
                Worker数量:
                <select id="worker-count">
                    <option value="1">1</option>
                    <option value="2">2</option>
                    <option value="4" selected>4</option>
                    <option value="8">8</option>
                </select>
            </label>
        </div>
    </section>
    
    <!-- 性能监控 -->
    <section class="performance-monitor">
        <h2>性能监控</h2>
        <div class="monitor-display">
            <div class="metric">
                <h3>主线程</h3>
                <p>处理时间: <span id="main-time">-</span></p>
                <p>CPU使用率: <span id="main-cpu">-</span></p>
                <p>内存使用: <span id="main-memory">-</span></p>
            </div>
            <div class="metric">
                <h3>Worker线程</h3>
                <p>处理时间: <span id="worker-time">-</span></p>
                <p>并行度: <span id="parallelism">-</span></p>
                <p>效率提升: <span id="efficiency">-</span></p>
            </div>
        </div>
        
        <div class="progress-bars">
            <div class="progress-item">
                <label>主线程进度:</label>
                <progress id="main-progress" max="100" value="0"></progress>
                <span id="main-progress-text">0%</span>
            </div>
            <div class="progress-item">
                <label>Worker进度:</label>
                <progress id="worker-progress" max="100" value="0"></progress>
                <span id="worker-progress-text">0%</span>
            </div>
        </div>
    </section>
    
    <!-- 结果对比 -->
    <section class="results-comparison">
        <h2>结果对比</h2>
        <div id="comparison-chart" role="img" aria-label="性能对比图表"></div>
        <div id="results-summary" role="region" aria-live="polite"></div>
    </section>
    
    <!-- 实时界面响应测试 -->
    <section class="responsiveness-test">
        <h2>界面响应性测试</h2>
        <div class="interactive-elements">
            <button id="ui-test-button">点击测试响应性</button>
            <input type="range" id="ui-test-slider" min="0" max="100" value="50">
            <span id="slider-value">50</span>
        </div>
        <div id="responsiveness-log" role="log" aria-live="polite"></div>
    </section>
    
    <script>
        // Web Workers性能优化实现
        document.addEventListener('DOMContentLoaded', function() {
            const dataSizeSelect = document.getElementById('data-size');
            const workerCountSelect = document.getElementById('worker-count');
            const mainTime = document.getElementById('main-time');
            const workerTime = document.getElementById('worker-time');
            const mainCpu = document.getElementById('main-cpu');
            const mainMemory = document.getElementById('main-memory');
            const parallelism = document.getElementById('parallelism');
            const efficiency = document.getElementById('efficiency');
            const mainProgress = document.getElementById('main-progress');
            const workerProgress = document.getElementById('worker-progress');
            const mainProgressText = document.getElementById('main-progress-text');
            const workerProgressText = document.getElementById('worker-progress-text');
            const resultsSummary = document.getElementById('results-summary');
            const responsivenessLog = document.getElementById('responsiveness-log');
            const uiTestButton = document.getElementById('ui-test-button');
            const uiTestSlider = document.getElementById('ui-test-slider');
            const sliderValue = document.getElementById('slider-value');
            
            let workers = [];
            let performanceData = [];
            
            // 界面响应性测试
            uiTestButton.addEventListener('click', function() {
                const timestamp = performance.now();
                logResponsiveness(`按钮点击响应时间: ${timestamp.toFixed(2)}ms`);
            });
            
            uiTestSlider.addEventListener('input', function() {
                sliderValue.textContent = this.value;
                logResponsiveness(`滑块值更新: ${this.value}`);
            });
            
            // 主线程处理测试
            document.getElementById('test-main-thread').addEventListener('click', function() {
                const dataSize = parseInt(dataSizeSelect.value);
                testMainThreadProcessing(dataSize);
            });
            
            // Worker线程处理测试
            document.getElementById('test-worker-thread').addEventListener('click', function() {
                const dataSize = parseInt(dataSizeSelect.value);
                testWorkerThreadProcessing(dataSize);
            });
            
            // 并行处理测试
            document.getElementById('test-parallel').addEventListener('click', function() {
                const dataSize = parseInt(dataSizeSelect.value);
                const workerCount = parseInt(workerCountSelect.value);
                testParallelProcessing(dataSize, workerCount);
            });
            
            // 批处理测试
            document.getElementById('test-batch').addEventListener('click', function() {
                const dataSize = parseInt(dataSizeSelect.value);
                const workerCount = parseInt(workerCountSelect.value);
                testBatchProcessing(dataSize, workerCount);
            });
            
            // 主线程处理
            function testMainThreadProcessing(dataSize) {
                const startTime = performance.now();
                const startMemory = performance.memory ? performance.memory.usedJSHeapSize : 0;
                
                // 生成测试数据
                const data = generateTestData(dataSize);
                
                // 模拟CPU密集型任务
                let progress = 0;
                const batchSize = Math.ceil(dataSize / 100);
                
                function processBatch(index) {
                    const endIndex = Math.min(index + batchSize, dataSize);
                    
                    // 处理数据批次
                    for (let i = index; i < endIndex; i++) {
                        data[i] = Math.sqrt(data[i]) * Math.sin(data[i]);
                    }
                    
                    progress = Math.round((endIndex / dataSize) * 100);
                    updateProgress(mainProgress, mainProgressText, progress);
                    
                    if (endIndex < dataSize) {
                        // 使用setTimeout避免完全阻塞UI
                        setTimeout(() => processBatch(endIndex), 0);
                    } else {
                        // 处理完成
                        const endTime = performance.now();
                        const endMemory = performance.memory ? performance.memory.usedJSHeapSize : 0;
                        const processingTime = endTime - startTime;
                        const memoryUsed = endMemory - startMemory;
                        
                        mainTime.textContent = processingTime.toFixed(2) + 'ms';
                        mainMemory.textContent = formatBytes(memoryUsed);
                        
                        recordPerformanceData('主线程', processingTime, 1, dataSize);
                        updateResultsSummary();
                    }
                }
                
                processBatch(0);
            }
            
            // Worker线程处理
            function testWorkerThreadProcessing(dataSize) {
                const startTime = performance.now();
                
                const worker = new Worker('performance-worker.js');
                
                worker.onmessage = function(e) {
                    if (e.data.type === 'progress') {
                        updateProgress(workerProgress, workerProgressText, e.data.progress);
                    } else if (e.data.type === 'complete') {
                        const endTime = performance.now();
                        const processingTime = endTime - startTime;
                        
                        workerTime.textContent = processingTime.toFixed(2) + 'ms';
                        parallelism.textContent = '1';
                        
                        recordPerformanceData('Worker线程', processingTime, 1, dataSize);
                        updateResultsSummary();
                        
                        worker.terminate();
                    }
                };
                
                worker.onerror = function(e) {
                    logResponsiveness('Worker错误: ' + e.message);
                };
                
                worker.postMessage({
                    type: 'process',
                    dataSize: dataSize
                });
            }
            
            // 并行处理
            function testParallelProcessing(dataSize, workerCount) {
                const startTime = performance.now();
                const chunkSize = Math.ceil(dataSize / workerCount);
                
                let completedWorkers = 0;
                let totalProgress = 0;
                
                workers = [];
                
                for (let i = 0; i < workerCount; i++) {
                    const worker = new Worker('performance-worker.js');
                    const startIndex = i * chunkSize;
                    const endIndex = Math.min(startIndex + chunkSize, dataSize);
                    
                    worker.onmessage = function(e) {
                        if (e.data.type === 'progress') {
                            totalProgress += e.data.progress / workerCount;
                            updateProgress(workerProgress, workerProgressText, Math.round(totalProgress));
                        } else if (e.data.type === 'complete') {
                            completedWorkers++;
                            
                            if (completedWorkers === workerCount) {
                                const endTime = performance.now();
                                const processingTime = endTime - startTime;
                                
                                workerTime.textContent = processingTime.toFixed(2) + 'ms';
                                parallelism.textContent = workerCount;
                                
                                recordPerformanceData('并行处理', processingTime, workerCount, dataSize);
                                updateResultsSummary();
                                
                                // 清理Workers
                                workers.forEach(w => w.terminate());
                                workers = [];
                            }
                        }
                    };
                    
                    worker.postMessage({
                        type: 'processChunk',
                        startIndex: startIndex,
                        endIndex: endIndex,
                        workerId: i
                    });
                    
                    workers.push(worker);
                }
            }
            
            // 批处理
            function testBatchProcessing(dataSize, workerCount) {
                const startTime = performance.now();
                const batchSize = Math.ceil(dataSize / (workerCount * 10)); // 更小的批次
                
                let processedBatches = 0;
                let totalBatches = Math.ceil(dataSize / batchSize);
                let currentBatch = 0;
                
                workers = [];
                
                function createWorker() {
                    const worker = new Worker('performance-worker.js');
                    
                    worker.onmessage = function(e) {
                        if (e.data.type === 'complete') {
                            processedBatches++;
                            const progress = Math.round((processedBatches / totalBatches) * 100);
                            updateProgress(workerProgress, workerProgressText, progress);
                            
                            if (currentBatch < totalBatches) {
                                // 处理下一批
                                const startIndex = currentBatch * batchSize;
                                const endIndex = Math.min(startIndex + batchSize, dataSize);
                                
                                worker.postMessage({
                                    type: 'processChunk',
                                    startIndex: startIndex,
                                    endIndex: endIndex,
                                    workerId: currentBatch
                                });
                                
                                currentBatch++;
                            } else {
                                // 所有批次完成
                                worker.terminate();
                                
                                if (processedBatches >= totalBatches) {
                                    const endTime = performance.now();
                                    const processingTime = endTime - startTime;
                                    
                                    workerTime.textContent = processingTime.toFixed(2) + 'ms';
                                    parallelism.textContent = workerCount + ' (批处理)';
                                    
                                    recordPerformanceData('批处理', processingTime, workerCount, dataSize);
                                    updateResultsSummary();
                                }
                            }
                        }
                    };
                    
                    return worker;
                }
                
                // 创建初始Workers
                for (let i = 0; i < workerCount && i < totalBatches; i++) {
                    const worker = createWorker();
                    const startIndex = currentBatch * batchSize;
                    const endIndex = Math.min(startIndex + batchSize, dataSize);
                    
                    worker.postMessage({
                        type: 'processChunk',
                        startIndex: startIndex,
                        endIndex: endIndex,
                        workerId: currentBatch
                    });
                    
                    currentBatch++;
                    workers.push(worker);
                }
            }
            
            // 生成测试数据
            function generateTestData(size) {
                const data = new Array(size);
                for (let i = 0; i < size; i++) {
                    data[i] = Math.random() * 1000;
                }
                return data;
            }
            
            // 更新进度
            function updateProgress(progressElement, textElement, progress) {
                progressElement.value = progress;
                textElement.textContent = progress + '%';
            }
            
            // 记录性能数据
            function recordPerformanceData(method, time, workers, dataSize) {
                performanceData.push({
                    method: method,
                    time: time,
                    workers: workers,
                    dataSize: dataSize,
                    timestamp: new Date()
                });
            }
            
            // 更新结果摘要
            function updateResultsSummary() {
                if (performanceData.length < 2) return;
                
                const latest = performanceData[performanceData.length - 1];
                const baseline = performanceData.find(d => d.method === '主线程');
                
                if (baseline && latest.method !== '主线程') {
                    const speedup = baseline.time / latest.time;
                    efficiency.textContent = speedup.toFixed(2) + 'x';
                }
                
                let summaryHtml = '<h3>性能测试结果</h3>';
                performanceData.forEach(data => {
                    summaryHtml += `
                        <div class="result-item">
                            <h4>${data.method}</h4>
                            <p>处理时间: ${data.time.toFixed(2)}ms</p>
                            <p>Worker数: ${data.workers}</p>
                            <p>数据量: ${data.dataSize.toLocaleString()}</p>
                        </div>
                    `;
                });
                
                resultsSummary.innerHTML = summaryHtml;
            }
            
            // 记录响应性
            function logResponsiveness(message) {
                const logEntry = document.createElement('div');
                logEntry.textContent = `${new Date().toLocaleTimeString()}: ${message}`;
                responsivenessLog.appendChild(logEntry);
                
                // 限制日志数量
                if (responsivenessLog.children.length > 10) {
                    responsivenessLog.removeChild(responsivenessLog.firstChild);
                }
            }
            
            // 格式化字节
            function formatBytes(bytes) {
                if (bytes === 0) return '0 B';
                const k = 1024;
                const sizes = ['B', 'KB', 'MB', 'GB'];
                const i = Math.floor(Math.log(bytes) / Math.log(k));
                return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
            }
        });
    </script>
</body>
</html>

9.4.5 实际使用场景

数据处理和分析

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>数据处理Worker应用</title>
</head>
<body>
    <h1>数据处理Worker应用</h1>
    
    <!-- 数据生成控制 -->
    <section class="data-control">
        <h2>数据生成</h2>
        <div class="control-group">
            <label>数据量: <input type="number" id="data-size" value="100000" min="1000" max="10000000"></label>
            <button id="generate-data">生成数据</button>
            <button id="clear-data">清除数据</button>
        </div>
        <div class="data-info">
            <p>当前数据量: <span id="current-data-size">0</span></p>
            <p>数据大小: <span id="data-memory">0 KB</span></p>
        </div>
    </section>
    
    <!-- 处理任务 -->
    <section class="processing-tasks">
        <h2>处理任务</h2>
        <div class="task-buttons">
            <button id="sort-data">排序数据</button>
            <button id="filter-data">过滤数据</button>
            <button id="aggregate-data">聚合统计</button>
            <button id="transform-data">数据转换</button>
        </div>
        <div class="task-progress">
            <progress id="task-progress" max="100" value="0"></progress>
            <span id="progress-text">0%</span>
        </div>
    </section>
    
    <!-- 结果展示 -->
    <section class="results">
        <h2>处理结果</h2>
        <div id="results-display" role="region" aria-live="polite"></div>
    </section>
    
    <script>
        // 数据处理Worker应用实现
        document.addEventListener('DOMContentLoaded', function() {
            const dataSizeInput = document.getElementById('data-size');
            const currentDataSize = document.getElementById('current-data-size');
            const dataMemory = document.getElementById('data-memory');
            const taskProgress = document.getElementById('task-progress');
            const progressText = document.getElementById('progress-text');
            const resultsDisplay = document.getElementById('results-display');
            
            let currentData = null;
            let processingWorker = null;
            
            // 生成数据
            document.getElementById('generate-data').addEventListener('click', function() {
                const size = parseInt(dataSizeInput.value);
                generateData(size);
            });
            
            // 清除数据
            document.getElementById('clear-data').addEventListener('click', function() {
                currentData = null;
                currentDataSize.textContent = '0';
                dataMemory.textContent = '0 KB';
                resultsDisplay.innerHTML = '';
            });
            
            // 处理任务
            document.getElementById('sort-data').addEventListener('click', () => {
                processData('sort');
            });
            
            document.getElementById('filter-data').addEventListener('click', () => {
                processData('filter');
            });
            
            document.getElementById('aggregate-data').addEventListener('click', () => {
                processData('aggregate');
            });
            
            document.getElementById('transform-data').addEventListener('click', () => {
                processData('transform');
            });
            
            // 生成数据
            function generateData(size) {
                if (processingWorker) {
                    processingWorker.terminate();
                }
                
                processingWorker = new Worker('data-processing-worker.js');
                
                processingWorker.onmessage = function(e) {
                    if (e.data.type === 'dataGenerated') {
                        currentData = e.data.data;
                        currentDataSize.textContent = currentData.length.toLocaleString();
                        
                        // 计算内存使用
                        const memorySize = JSON.stringify(currentData).length;
                        dataMemory.textContent = (memorySize / 1024).toFixed(2) + ' KB';
                        
                        resultsDisplay.innerHTML = '<p>数据生成完成</p>';
                    }
                };
                
                processingWorker.postMessage({
                    type: 'generateData',
                    size: size
                });
            }
            
            // 处理数据
            function processData(operation) {
                if (!currentData) {
                    alert('请先生成数据');
                    return;
                }
                
                if (processingWorker) {
                    processingWorker.terminate();
                }
                
                processingWorker = new Worker('data-processing-worker.js');
                
                processingWorker.onmessage = function(e) {
                    if (e.data.type === 'progress') {
                        updateProgress(e.data.progress);
                    } else if (e.data.type === 'result') {
                        displayResult(e.data.result, operation);
                        updateProgress(100);
                    }
                };
                
                processingWorker.postMessage({
                    type: 'process',
                    operation: operation,
                    data: currentData
                });
            }
            
            // 更新进度
            function updateProgress(progress) {
                taskProgress.value = progress;
                progressText.textContent = progress + '%';
            }
            
            // 显示结果
            function displayResult(result, operation) {
                let resultHtml = `<h3>${getOperationName(operation)}完成</h3>`;
                
                switch (operation) {
                    case 'sort':
                        resultHtml += `
                            <p>排序耗时: ${result.duration}ms</p>
                            <p>排序算法: ${result.algorithm}</p>
                            <p>前5个值: ${result.preview.join(', ')}</p>
                        `;
                        break;
                    case 'filter':
                        resultHtml += `
                            <p>过滤耗时: ${result.duration}ms</p>
                            <p>原始数据: ${result.originalCount}</p>
                            <p>过滤后: ${result.filteredCount}</p>
                            <p>过滤率: ${result.filterRate}%</p>
                        `;
                        break;
                    case 'aggregate':
                        resultHtml += `
                            <p>聚合耗时: ${result.duration}ms</p>
                            <p>总和: ${result.sum}</p>
                            <p>平均值: ${result.average}</p>
                            <p>最大值: ${result.max}</p>
                            <p>最小值: ${result.min}</p>
                        `;
                        break;
                    case 'transform':
                        resultHtml += `
                            <p>转换耗时: ${result.duration}ms</p>
                            <p>转换类型: ${result.transformType}</p>
                            <p>处理记录: ${result.processedCount}</p>
                        `;
                        break;
                }
                
                resultsDisplay.innerHTML = resultHtml;
            }
            
            // 获取操作名称
            function getOperationName(operation) {
                const names = {
                    'sort': '数据排序',
                    'filter': '数据过滤',
                    'aggregate': '数据聚合',
                    'transform': '数据转换'
                };
                return names[operation] || '数据处理';
            }
        });
    </script>
</body>
</html>

实时计算应用

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>实时计算Worker</title>
</head>
<body>
    <h1>实时计算Worker应用</h1>
    
    <!-- 计算控制 -->
    <section class="calculation-control">
        <h2>计算控制</h2>
        <div class="control-buttons">
            <button id="start-calculation">开始计算</button>
            <button id="pause-calculation">暂停计算</button>
            <button id="stop-calculation">停止计算</button>
            <button id="reset-calculation">重置计算</button>
        </div>
        <div class="calculation-settings">
            <label>计算强度: <input type="range" id="intensity" min="1" max="10" value="5"></label>
            <label>更新频率: <input type="range" id="frequency" min="1" max="60" value="30"> Hz</label>
        </div>
    </section>
    
    <!-- 实时显示 -->
    <section class="real-time-display">
        <h2>实时数据</h2>
        <div class="metrics-grid">
            <div class="metric-card">
                <h3>计算次数</h3>
                <div class="metric-value" id="calculation-count">0</div>
            </div>
            <div class="metric-card">
                <h3>计算速度</h3>
                <div class="metric-value" id="calculation-speed">0 /s</div>
            </div>
            <div class="metric-card">
                <h3>CPU使用率</h3>
                <div class="metric-value" id="cpu-usage">0%</div>
            </div>
            <div class="metric-card">
                <h3>内存使用</h3>
                <div class="metric-value" id="memory-usage">0 MB</div>
            </div>
        </div>
    </section>
    
    <!-- 计算结果 -->
    <section class="calculation-results">
        <h2>计算结果</h2>
        <div id="results-chart" role="img" aria-label="计算结果图表"></div>
        <div id="results-data" role="region" aria-live="polite"></div>
    </section>
    
    <script>
        // 实时计算Worker应用
        document.addEventListener('DOMContentLoaded', function() {
            const intensitySlider = document.getElementById('intensity');
            const frequencySlider = document.getElementById('frequency');
            const calculationCount = document.getElementById('calculation-count');
            const calculationSpeed = document.getElementById('calculation-speed');
            const cpuUsage = document.getElementById('cpu-usage');
            const memoryUsage = document.getElementById('memory-usage');
            const resultsChart = document.getElementById('results-chart');
            const resultsData = document.getElementById('results-data');
            
            let calculationWorker = null;
            let isCalculating = false;
            let startTime = null;
            let totalCalculations = 0;
            let resultsHistory = [];
            
            // 控制按钮
            document.getElementById('start-calculation').addEventListener('click', startCalculation);
            document.getElementById('pause-calculation').addEventListener('click', pauseCalculation);
            document.getElementById('stop-calculation').addEventListener('click', stopCalculation);
            document.getElementById('reset-calculation').addEventListener('click', resetCalculation);
            
            // 参数变化
            intensitySlider.addEventListener('input', updateSettings);
            frequencySlider.addEventListener('input', updateSettings);
            
            // 开始计算
            function startCalculation() {
                if (isCalculating) return;
                
                isCalculating = true;
                startTime = Date.now();
                
                if (calculationWorker) {
                    calculationWorker.terminate();
                }
                
                calculationWorker = new Worker('real-time-calculation-worker.js');
                
                calculationWorker.onmessage = function(e) {
                    handleCalculationResult(e.data);
                };
                
                calculationWorker.postMessage({
                    type: 'start',
                    intensity: parseInt(intensitySlider.value),
                    frequency: parseInt(frequencySlider.value)
                });
            }
            
            // 暂停计算
            function pauseCalculation() {
                if (!isCalculating) return;
                
                isCalculating = false;
                
                if (calculationWorker) {
                    calculationWorker.postMessage({
                        type: 'pause'
                    });
                }
            }
            
            // 停止计算
            function stopCalculation() {
                isCalculating = false;
                
                if (calculationWorker) {
                    calculationWorker.postMessage({
                        type: 'stop'
                    });
                    calculationWorker.terminate();
                    calculationWorker = null;
                }
            }
            
            // 重置计算
            function resetCalculation() {
                stopCalculation();
                
                totalCalculations = 0;
                resultsHistory = [];
                startTime = null;
                
                updateDisplay();
                resultsChart.innerHTML = '';
                resultsData.innerHTML = '';
            }
            
            // 更新设置
            function updateSettings() {
                if (calculationWorker && isCalculating) {
                    calculationWorker.postMessage({
                        type: 'updateSettings',
                        intensity: parseInt(intensitySlider.value),
                        frequency: parseInt(frequencySlider.value)
                    });
                }
            }
            
            // 处理计算结果
            function handleCalculationResult(data) {
                switch (data.type) {
                    case 'result':
                        totalCalculations++;
                        resultsHistory.push(data.result);
                        
                        // 限制历史记录数量
                        if (resultsHistory.length > 100) {
                            resultsHistory.shift();
                        }
                        
                        updateDisplay();
                        updateChart();
                        break;
                    
                    case 'performance':
                        updatePerformanceMetrics(data.metrics);
                        break;
                    
                    case 'error':
                        console.error('计算错误:', data.error);
                        break;
                }
            }
            
            // 更新显示
            function updateDisplay() {
                calculationCount.textContent = totalCalculations.toLocaleString();
                
                if (startTime) {
                    const elapsed = (Date.now() - startTime) / 1000;
                    const speed = totalCalculations / elapsed;
                    calculationSpeed.textContent = speed.toFixed(1) + ' /s';
                }
                
                if (resultsHistory.length > 0) {
                    const latest = resultsHistory[resultsHistory.length - 1];
                    resultsData.innerHTML = `
                        <h3>最新结果</h3>
                        <p>计算值: ${latest.value}</p>
                        <p>计算时间: ${latest.duration}ms</p>
                        <p>时间戳: ${new Date(latest.timestamp).toLocaleTimeString()}</p>
                    `;
                }
            }
            
            // 更新图表
            function updateChart() {
                if (resultsHistory.length === 0) return;
                
                const chartData = resultsHistory.slice(-50); // 显示最近50个点
                const max = Math.max(...chartData.map(r => r.value));
                const min = Math.min(...chartData.map(r => r.value));
                
                let chartHtml = '<div class="chart-container">';
                chartHtml += '<h3>计算结果趋势</h3>';
                chartHtml += '<div class="chart-line">';
                
                chartData.forEach((result, index) => {
                    const normalized = (result.value - min) / (max - min || 1);
                    const height = normalized * 100;
                    chartHtml += `<div class="chart-point" style="height: ${height}%" title="${result.value}"></div>`;
                });
                
                chartHtml += '</div>';
                chartHtml += `<p>范围: ${min.toFixed(2)} - ${max.toFixed(2)}</p>`;
                chartHtml += '</div>';
                
                resultsChart.innerHTML = chartHtml;
            }
            
            // 更新性能指标
            function updatePerformanceMetrics(metrics) {
                cpuUsage.textContent = metrics.cpuUsage + '%';
                memoryUsage.textContent = (metrics.memoryUsage / 1024 / 1024).toFixed(2) + ' MB';
            }
        });
    </script>
</body>
</html>

关键知识点总结

1. Web Workers基本概念

  • 多线程处理:在后台线程执行JavaScript代码,避免阻塞UI线程
  • 消息传递:通过postMessage和onmessage进行主线程与Worker线程的通信
  • 独立环境:Worker拥有独立的全局作用域,无法直接访问DOM
  • 资源隔离:提供安全的代码执行环境

2. Worker类型和特点

  • Dedicated Worker:专用Worker,只能被创建它的脚本使用
  • Shared Worker:共享Worker,可以被多个脚本或窗口共享
  • Service Worker:服务工作线程,主要用于离线缓存和推送通知

3. 通信机制

  • 消息传递:使用postMessage发送数据,onmessage接收数据
  • 数据传输:支持结构化克隆和转移对象(Transferable Objects)
  • 错误处理:使用onerror和onmessageerror处理错误

4. 性能优化策略

  • 任务分解:将大任务分解为小任务,避免长时间阻塞
  • 并行处理:使用多个Worker并行处理不同的任务
  • 批处理:批量处理数据,减少通信开销
  • 资源管理:合理创建和销毁Worker,避免资源泄漏

5. 实际应用场景

  • 数据处理:大数据排序、过滤、聚合计算
  • 图像处理:图像滤镜、格式转换、压缩
  • 加密解密:密码学计算、数据加密
  • 实时通信:WebSocket消息处理、实时数据分析

常见问题解答

Q1: Web Workers能访问哪些Web API?

A1: Worker可以访问大部分Web API,但不能访问DOM、父对象的属性和某些特定的API。可以访问XMLHttpRequest、WebSockets、IndexedDB等。

Q2: 如何在Worker中处理大量数据?

A2: 使用批处理技术,将大数据分块处理,定期向主线程报告进度,避免内存溢出。

Q3: Worker的生命周期是怎样的?

A3: Worker在创建后开始运行,可以通过terminate()方法终止,或者在Worker脚本执行完毕后自动结束。

Q4: 如何调试Web Workers?

A4: 使用浏览器开发者工具的Sources面板,可以在Worker脚本中设置断点进行调试。

Q5: Worker的性能开销有多大?

A5: 创建Worker有一定开销,但对于CPU密集型任务,性能收益通常远大于开销。

学习资源推荐

官方文档

实践项目

  • 在线图像编辑器
  • 大数据可视化工具
  • 实时聊天应用
  • 科学计算平台

相关技术

  • SharedArrayBuffer:共享内存缓冲区
  • OffscreenCanvas:离屏画布
  • WebAssembly:高性能计算模块
  • Atomics:原子操作

通过本节的学习,您应该能够熟练使用Web Workers创建高性能的多线程应用,优化用户体验,处理复杂的计算任务。