<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>SharedWorker 与 Worker 的区别</title><style>* {box-sizing: border-box;margin: 0;padding: 0;font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;}body {background-color: #f5f7fa;color: #333;line-height: 1.6;padding: 20px;}.container {max-width: 1200px;margin: 0 auto;}header {text-align: center;margin-bottom: 40px;padding: 20px;background: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%);color: white;border-radius: 10px;box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);}h1 {font-size: 2.5rem;margin-bottom: 10px;}.subtitle {font-size: 1.2rem;opacity: 0.9;}.comparison {display: flex;flex-wrap: wrap;gap: 30px;margin-bottom: 40px;}.card {flex: 1;min-width: 300px;background: white;border-radius: 10px;padding: 25px;box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);transition: transform 0.3s ease;}.card:hover {transform: translateY(-5px);}.worker-card {border-top: 5px solid #ff6b6b;}.shared-worker-card {border-top: 5px solid #4cd97b;}.card h2 {display: flex;align-items: center;margin-bottom: 20px;font-size: 1.8rem;}.worker-card h2:before {content: "🔒";margin-right: 10px;}.shared-worker-card h2:before {content: "🔗";margin-right: 10px;}.feature-list {list-style-type: none;margin: 20px 0;}.feature-list li {padding: 10px 0;border-bottom: 1px solid #eee;display: flex;align-items: center;}.feature-list li:before {content: "✓";margin-right: 10px;font-weight: bold;}.worker-card .feature-list li:before {color: #ff6b6b;}.shared-worker-card .feature-list li:before {color: #4cd97b;}.demo-section {display: flex;flex-wrap: wrap;gap: 30px;margin-bottom: 40px;}.demo-panel {flex: 1;min-width: 300px;background: white;border-radius: 10px;padding: 25px;box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);}.demo-panel h3 {margin-bottom: 20px;font-size: 1.5rem;color: #444;}.demo-controls {display: flex;gap: 10px;margin-bottom: 20px;flex-wrap: wrap;}button {padding: 10px 15px;border: none;border-radius: 5px;cursor: pointer;font-weight: bold;transition: all 0.3s ease;}.worker-btn {background-color: #ff6b6b;color: white;}.worker-btn:hover {background-color: #ff5252;}.shared-worker-btn {background-color: #4cd97b;color: white;}.shared-worker-btn:hover {background-color: #38cc6c;}.output {background-color: #f8f9fa;border: 1px solid #e9ecef;border-radius: 5px;padding: 15px;min-height: 150px;max-height: 300px;overflow-y: auto;font-family: 'Courier New', monospace;font-size: 0.9rem;white-space: pre-wrap;}.status {margin-top: 10px;padding: 10px;border-radius: 5px;font-weight: bold;}.status.connected {background-color: #e8f5e9;color: #2e7d32;}.status.disconnected {background-color: #ffebee;color: #c62828;}.explanation {background-color: #fff3cd;border: 1px solid #ffeaa7;border-radius: 5px;padding: 15px;margin: 20px 0;}.code-example {background-color: #2d2d2d;color: #f8f8f2;border-radius: 5px;padding: 20px;margin-top: 30px;overflow-x: auto;}.code-example h3 {color: #f8f8f2;margin-bottom: 15px;}pre {white-space: pre-wrap;line-height: 1.5;}.highlight {color: #ff79c6;}.comment {color: #6272a4;}.browser-support {background: white;border-radius: 10px;padding: 25px;box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);margin-bottom: 40px;}.browser-support h2 {margin-bottom: 20px;text-align: center;color: #444;}.support-table {width: 100%;border-collapse: collapse;}.support-table th, .support-table td {padding: 12px 15px;text-align: left;border-bottom: 1px solid #eee;}.support-table th {background-color: #f8f9fa;}.supported {color: #4cd97b;font-weight: bold;}.not-supported {color: #ff6b6b;font-weight: bold;}footer {text-align: center;padding: 20px;color: #666;font-size: 0.9rem;}@media (max-width: 768px) {.comparison, .demo-section {flex-direction: column;}.card, .demo-panel {min-width: 100%;}}</style>
</head>
<body><div class="container"><header><h1>SharedWorker 与 Worker 的区别</h1><p class="subtitle">理解Web Workers中的两种不同类型及其应用场景</p></header><div class="explanation"><h3>⚠️ 重要说明:SharedWorker的限制</h3><p>由于浏览器安全限制,使用Blob URL创建的SharedWorker在不同标签页中无法真正共享。每个标签页会创建独立的SharedWorker实例。</p><p>要体验真正的SharedWorker共享功能,需要:</p><ol><li>通过HTTP服务器运行此页面(不能直接打开HTML文件)</li><li>使用固定的JS文件路径创建SharedWorker</li></ol><p>当前演示使用模拟方式展示SharedWorker的概念和工作原理。</p></div><div class="comparison"><div class="card worker-card"><h2>专用Worker (Dedicated Worker)</h2><p>专用Worker与创建它的脚本一对一关联,只能被创建它的页面访问。</p><ul class="feature-list"><li>与创建它的脚本一对一关联</li><li>生命周期与创建页面绑定</li><li>无法被其他页面或Worker访问</li><li>所有主流浏览器都支持</li><li>适用于单页面内的复杂计算任务</li></ul></div><div class="card shared-worker-card"><h2>共享Worker (SharedWorker)</h2><p>共享Worker可以被多个脚本共享,只要这些脚本与共享Worker同源。</p><ul class="feature-list"><li>可以被多个浏览器上下文(窗口、iframe等)共享</li><li>生命周期独立于创建它的页面</li><li>通过端口(port)与不同页面通信</li><li>浏览器支持相对较少</li><li>适用于多标签页应用的数据同步</li></ul></div></div><div class="demo-section"><div class="demo-panel"><h3>Worker 演示</h3><div class="demo-controls"><button class="worker-btn" id="startWorker">启动Worker</button><button class="worker-btn" id="sendToWorker">发送消息</button><button class="worker-btn" id="terminateWorker">终止Worker</button></div><div class="output" id="workerOutput">Worker输出将显示在这里...</div><div id="workerStatus" class="status disconnected">Worker状态: 未连接</div></div><div class="demo-panel"><h3>SharedWorker 演示(模拟)</h3><div class="demo-controls"><button class="shared-worker-btn" id="startSharedWorker">启动SharedWorker</button><button class="shared-worker-btn" id="sendToSharedWorker">发送消息</button><button class="shared-worker-btn" id="terminateSharedWorker">断开连接</button><button class="shared-worker-btn" id="newTab">在新标签页中打开</button></div><div class="output" id="sharedWorkerOutput">SharedWorker输出将显示在这里...</div><div id="sharedWorkerStatus" class="status disconnected">SharedWorker状态: 未连接</div><p style="margin-top: 10px; font-size: 0.9rem; color: #666;">提示:由于浏览器限制,当前演示为模拟效果。真实环境中需要服务器支持。</p></div></div><div class="code-example"><h3>真实环境中的SharedWorker代码示例</h3><pre><code>// <span class="comment">// 主页面代码 (main.html)</span>
<span class="comment">// 使用固定的JS文件路径创建SharedWorker</span>
const sharedWorker = new SharedWorker('/js/shared-worker.js');sharedWorker.port.start();sharedWorker.port.onmessage = function(event) {console.log('收到来自SharedWorker的消息:', event.data);
};<span class="comment">// 发送消息到SharedWorker</span>
sharedWorker.port.postMessage('Hello from main page!');<span class="comment">// SharedWorker代码 (shared-worker.js)</span>
let connectionCount = 0;
let ports = [];self.onconnect = function(event) {<span class="comment">// 获取连接的端口</span>const port = event.ports[0];connectionCount++;<span class="comment">// 保存端口引用</span>ports.push(port);<span class="comment">// 向新连接的客户端发送欢迎消息</span>port.postMessage(`欢迎!你是第${connectionCount}个连接的客户端`);<span class="comment">// 向所有客户端广播连接更新</span>broadcastMessage(`系统通知:当前有${connectionCount}个客户端连接`);<span class="comment">// 处理来自客户端的消息</span>port.onmessage = function(event) {const message = event.data;broadcastMessage(`客户端消息: ${message}`);};<span class="comment">// 处理端口关闭</span>port.onclose = function() {const index = ports.indexOf(port);if (index > -1) {ports.splice(index, 1);connectionCount--;broadcastMessage(`系统通知:客户端断开,剩余${connectionCount}个连接`);}};port.start();
};function broadcastMessage(message) {ports.forEach(port => {port.postMessage(message);});
}</code></pre></div><div class="browser-support"><h2>浏览器支持情况</h2><table class="support-table"><thead><tr><th>浏览器</th><th>Worker</th><th>SharedWorker</th></tr></thead><tbody><tr><td>Chrome</td><td class="supported">✓ 支持</td><td class="supported">✓ 支持</td></tr><tr><td>Firefox</td><td class="supported">✓ 支持</td><td class="supported">✓ 支持</td></tr><tr><td>Safari</td><td class="supported">✓ 支持</td><td class="supported">✓ 支持 (14.1+)</td></tr><tr><td>Edge</td><td class="supported">✓ 支持</td><td class="supported">✓ 支持</td></tr><tr><td>Internet Explorer</td><td class="supported">✓ 支持 (10+)</td><td class="not-supported">✗ 不支持</td></tr></tbody></table></div><footer><p>© 2023 Web Workers 演示 | 注意:真正的SharedWorker需要服务器环境才能正常工作</p></footer></div><script>// Worker 演示代码let worker;const workerOutput = document.getElementById('workerOutput');const workerStatus = document.getElementById('workerStatus');document.getElementById('startWorker').addEventListener('click', function() {if (worker) {workerOutput.textContent += '\nWorker已经存在,先终止旧Worker';worker.terminate();}// 创建Worker的Blob URLconst workerScript = `let messageCount = 0;self.onmessage = function(e) {messageCount++;const message = e.data;self.postMessage('Worker收到第' + messageCount + '条消息: ' + message + ' | 时间: ' + new Date().toLocaleTimeString());// 模拟一些工作let result = 0;for (let i = 0; i < 10000000; i++) {result += Math.sqrt(i);}self.postMessage('计算完成! 结果: ' + result.toString().substring(0, 10) + '...');};`;const blob = new Blob([workerScript], { type: 'application/javascript' });const blobUrl = URL.createObjectURL(blob);worker = new Worker(blobUrl);worker.onmessage = function(e) {workerOutput.textContent += '\n' + e.data;workerOutput.scrollTop = workerOutput.scrollHeight;};worker.onerror = function(e) {workerOutput.textContent += '\nWorker错误: ' + e.message;};workerOutput.textContent = 'Worker已启动!';workerStatus.textContent = 'Worker状态: 已连接';workerStatus.className = 'status connected';});document.getElementById('sendToWorker').addEventListener('click', function() {if (worker) {worker.postMessage('消息 #' + Math.floor(Math.random() * 100));} else {workerOutput.textContent += '\n请先启动Worker!';}});document.getElementById('terminateWorker').addEventListener('click', function() {if (worker) {worker.terminate();worker = null;workerOutput.textContent += '\nWorker已终止!';workerStatus.textContent = 'Worker状态: 未连接';workerStatus.className = 'status disconnected';}});// SharedWorker 模拟演示// 由于浏览器限制,我们使用localStorage模拟SharedWorker的共享效果let sharedWorker;const sharedWorkerOutput = document.getElementById('sharedWorkerOutput');const sharedWorkerStatus = document.getElementById('sharedWorkerStatus');// 生成唯一的页面IDconst pageId = 'page_' + Math.random().toString(36).substr(2, 9);let connectionCount = 1; // 模拟连接计数// 模拟SharedWorker的消息处理function simulateSharedWorker() {// 存储当前页面的连接状态localStorage.setItem('shared_worker_page_' + pageId, 'connected');// 计算"已连接"的页面数量let connectedPages = 0;for (let i = 0; i < localStorage.length; i++) {const key = localStorage.key(i);if (key.startsWith('shared_worker_page_') && localStorage.getItem(key) === 'connected') {connectedPages++;}}// 模拟SharedWorker的响应return {connectionCount: connectedPages,pageId: pageId};}document.getElementById('startSharedWorker').addEventListener('click', function() {if (sharedWorker) {sharedWorkerOutput.textContent += '\nSharedWorker已经连接';return;}try {// 模拟SharedWorker连接const result = simulateSharedWorker();connectionCount = result.connectionCount;sharedWorker = {port: {postMessage: function(message) {// 模拟消息广播到所有"已连接"的页面const timestamp = new Date().toLocaleTimeString();const response = `SharedWorker收到消息: ${message} | 来自: ${pageId} | 时间: ${timestamp}`;// 存储消息以便其他页面可以读取(模拟广播)localStorage.setItem('shared_worker_broadcast', response);localStorage.setItem('shared_worker_broadcast_time', Date.now().toString());// 也显示在当前页面setTimeout(() => {sharedWorkerOutput.textContent += '\n' + response;sharedWorkerOutput.scrollTop = sharedWorkerOutput.scrollHeight;}, 100);},close: function() {localStorage.setItem('shared_worker_page_' + pageId, 'disconnected');sharedWorker = null;}}};// 模拟SharedWorker的欢迎消息sharedWorkerOutput.textContent = `SharedWorker已连接! (页面ID: ${pageId})`;sharedWorkerOutput.textContent += `\n欢迎! 当前有 ${connectionCount} 个客户端连接到SharedWorker`;sharedWorkerStatus.textContent = 'SharedWorker状态: 已连接';sharedWorkerStatus.className = 'status connected';// 监听其他页面的广播消息startBroadcastListener();} catch (e) {sharedWorkerOutput.textContent = 'SharedWorker启动失败: ' + e.message;}});document.getElementById('sendToSharedWorker').addEventListener('click', function() {if (sharedWorker) {sharedWorker.port.postMessage('消息 #' + Math.floor(Math.random() * 100));} else {sharedWorkerOutput.textContent += '\n请先启动SharedWorker!';}});document.getElementById('terminateSharedWorker').addEventListener('click', function() {if (sharedWorker) {sharedWorker.port.close();sharedWorker = null;sharedWorkerOutput.textContent += '\nSharedWorker连接已关闭!';sharedWorkerStatus.textContent = 'SharedWorker状态: 未连接';sharedWorkerStatus.className = 'status disconnected';// 停止监听广播stopBroadcastListener();}});document.getElementById('newTab').addEventListener('click', function() {window.open(window.location.href, '_blank');});// 广播监听器let broadcastListener;function startBroadcastListener() {let lastBroadcastTime = localStorage.getItem('shared_worker_broadcast_time') || '0';broadcastListener = setInterval(() => {const currentBroadcastTime = localStorage.getItem('shared_worker_broadcast_time');if (currentBroadcastTime && currentBroadcastTime !== lastBroadcastTime) {lastBroadcastTime = currentBroadcastTime;const message = localStorage.getItem('shared_worker_broadcast');if (message && !message.includes(pageId)) { // 不显示自己发送的消息sharedWorkerOutput.textContent += '\n' + message;sharedWorkerOutput.scrollTop = sharedWorkerOutput.scrollHeight;}}}, 500);}function stopBroadcastListener() {if (broadcastListener) {clearInterval(broadcastListener);broadcastListener = null;}}// 页面卸载时清理资源window.addEventListener('beforeunload', function() {if (worker) {worker.terminate();}if (sharedWorker) {localStorage.setItem('shared_worker_page_' + pageId, 'disconnected');stopBroadcastListener();}});</script>
</body>
</html>