JavaScript 引擎是单线程的,浏览器(宿主环境)是多线程的
当打开一个页面时,浏览器通常会启动以下线程:
当创建一个 Worker 时,浏览器会做一件特别的事:它专门为这个 Worker 又启动了一个全新的“JS 引擎线程”。
Web Worker 的核心价值就是:开辟一个独立的后台线程,专门跑这些复杂任务,让主线程专心处理用户界面,设计核心是 “完全隔离”。当执行 new Worker('task.js') 时,浏览器会为创建一个全新的 JS 执行环境。
工作流程举例:
// main.js (主线程)
const worker = new Worker('worker.js');
// 发送数据给 Worker 去处理
worker.postMessage({ type: 'CALC', data: 1000000000 });
// 监听 Worker 处理完成的消息
worker.onmessage = (event) => {
console.log('计算结果回来了:', event.data);
// 更新页面 UI
document.getElementById('result').innerText = event.data;
};
// worker.js (独立线程)
self.onmessage = (event) => {
if (event.data.type === 'CALC') {
let sum = 0;
// 这是一个极其耗时的循环,但页面不会卡顿!
for (let i = 0; i < event.data.data; i++) {
sum += i;
}
// 把结果发回主线程
self.postMessage(sum);
}
};Service Worker(简称 SW)最核心的能力是:拦截(Intercept)。
传统网页严重依赖网络,一旦断网,页面就彻底无法访问,用户看到的会是“无法连接到网络”的提示,体验非常差
在没有 SW 之前,网页发出的请求(Fetch/XHR)是直接去互联网的。有了 SW 之后,所有的请求都要先经过它。它像一个中间人,可以决定:
注册 (Register)
↓
安装 (Install) ← 适合预缓存静态资源
↓
等待 (Waiting) ← 关键!控制权交接的“冷静期”
↓
激活 (Activate) ← 适合清理旧缓存
↓
运行 (Fetch/Message) ← 拦截请求、后台同步等
↓
废弃 (Redundant) ← 被新版本取代或安装失败当网络掉线时,SW 拦截请求并返回缓存
在用户还没点击下一页时,SW 已经在后台偷偷把下一页的资源下载好了
Web Worker 随页面关闭而死亡,但 Service Worker 是独立于页面生命周期的
当你注册了一个 Service Worker,浏览器会把它的脚本代码和它开辟的 Cache Storage(缓存库) 永久保存在用户的本地磁盘上。
用户再次打开网页:它立刻跳出来拦截第一个 fetch 请求。
收到服务器推送(Push):即使网页没开,服务器发来个通知,SW 也会醒来弹出提示。
后台同步(Sync):你之前没发出去的评论,在网络恢复的一刻,SW 自动醒来帮你在后台发出去。
SharedWorker 是一种可在多个同源浏览上下文(标签页、iframe、弹窗)之间共享的 Web Worker。它独立于所有页面运行,通过消息端口与各个页面通信
执行 new SharedWorker('/worker.js')
│
├── 检查是否已有同名 Worker
│
├── 没有 → 创建新 Worker
│ └── worker.js 开始执行
│ └── self.onconnect 等待连接
│
└── 已有 → 复用现有 Worker
└── 触发 worker.js 的 connect 事件
└── 新窗口端口加入数组
│
▼
页面获得通信端口,可以收发消息
│
▼
用户打开新标签页(同源)
│
▼
新页面也执行 new SharedWorker('/worker.js')
│
└── 检测到已有 Worker → 复用
└── 触发 worker.js 的 connect 事件
└── 新窗口端口加入数组port.start() - 接收页面消息// worker.js
self.addEventListener('connect', (e) => {
const port = e.ports[0];
// 🎯 必须调用:让 Worker 能够接收页面发来的消息
port.start();
// 现在可以监听页面消息了
port.addEventListener('message', (msg) => {
console.log('Worker 收到页面消息:', msg.data);
// 处理业务逻辑...
});
});worker.port.start() - 接收 Worker 消息// 页面
const worker = new SharedWorker('worker.js');
// 🎯 必须调用:让页面能够接收 Worker 发来的消息
worker.port.start();
// 现在可以监听 Worker 消息了
worker.port.addEventListener('message', (e) => {
console.log('页面收到 Worker 消息:', e.data);
});