javascript 本身是单线程的,web workers 提供后台线程运行脚本以避免阻塞主线程,但无法操作 dom 或访问 window、document;dedicated worker 一对一通信,适用于计算密集型任务;需通过 postmessage 通信,支持 transferable objects 避免大数组拷贝开销;sharedarraybuffer + atomics 可实现真正共享内存,但须启用跨域隔离(coop/coep)且仅限 https 环境。

JavaScript 本身是单线程的,Web Workers 不是让 JS 变成多线程,而是提供一种在**后台线程中运行脚本**的机制,避开主线程阻塞。它不能操作 DOM,也不能访问 window、document 等全局对象——这点必须一开始就认清。
如何创建并使用一个 Dedicated Worker
最常用的是 DedicatedWorker,一对一通信,适合处理计算密集型任务(如图像处理、加密、大数据排序)。
- Worker 脚本必须放在独立的
.js文件中,不能是内联字符串或 Blob URL(部分浏览器限制) - 主线程用
new Worker('path/to/worker.js')实例化,Worker 内部用self.onmessage接收、self.postMessage发送 - 通信内容会自动序列化(结构化克隆算法),不支持函数、undefined、Promise、DOM 节点等
/* main.js */
const worker = new Worker('calc-worker.js');
worker.postMessage({ numbers: [1, 2, 3, 4, 5] });
<p>worker.onmessage = function(e) {
console.log('Result:', e.data); // { sum: 15 }
};</p><p>/<em> calc-worker.js </em>/
self.onmessage = function(e) {
const sum = e.data.numbers.reduce((a, b) => a + b, 0);
self.postMessage({ sum });
};为什么 postMessage 传大数组会卡顿?
因为默认走结构化克隆,对大对象(比如几 MB 的 ArrayBuffer 或嵌套深的 JSON)复制开销高。这时候要用 transferable objects 避免拷贝。
- 只支持
ArrayBuffer、MessagePort、ImageBitmap等少数类型 - 转移后原主线程的引用立即失效(变成
null),内存所有权交给 Worker - 写法是
postMessage(data, [buffer]),第二个参数是 transfer list
/* 主线程 */
const buffer = new ArrayBuffer(1024 * 1024);
const view = new Uint8Array(buffer);
view.fill(1);
<p>worker.postMessage({ data: buffer }, [buffer]); // ← 关键:转移</p><div class="aritcle_card flexRow">
<div class="artcardd flexRow">
<a class="aritcle_card_img" href="/ai/1699" title="Video Ocean"><img
src="https://img.php.cn/upload/ai_manual/000/969/633/68b6d3927b619815.png" alt="Video Ocean" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a href="/ai/1699" title="Video Ocean">Video Ocean</a>
<p>人人皆导演,让视频创作变得轻松自如</p>
</div>
<a href="/ai/1699" title="Video Ocean" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a>
</div>
</div><p><span>立即学习</span>“<a href="https://pan.quark.cn/s/c1c2c2ed740f" style="text-decoration: underline !important; color: blue; font-weight: bolder;" rel="nofollow" target="_blank">Java免费学习笔记(深入)</a></a>”;</p><p>/<em> Worker 内 </em>/
self.onmessage = function(e) {
const view = new Uint8Array(e.data.data); // 直接读,不拷贝
};SharedArrayBuffer + Atomics 能否真正共享内存?
可以,但有严格前提:必须启用跨域隔离(COOP/COEP 头),且现代浏览器默认禁用,仅限 HTTPS + 显式声明场景。
-
SharedArrayBuffer是一块可被多个线程直接读写的内存区域 -
Atomics提供原子操作(如Atomics.add()、Atomics.wait()),避免竞态 - 不加
Atomics直接读写仍是未定义行为,不是“线程安全”的捷径
没配好 COOP/COEP 时,控制台会报错:SharedArrayBuffer is not defined 或 Atomics is not defined —— 别硬试,先检查响应头是否含 Cross-Origin-Embedder-Policy: require-corp 和 Cross-Origin-Opener-Policy: same-origin。
真正难的从来不是调用 new Worker(),而是判断该不该用、数据怎么传、错误怎么捕获(worker.onerror 不会冒泡)、以及调试时看不到 Worker 中的 console 输出(得用 chrome://inspect 单独连)。










