必须满足跨域隔离、正确同步、内存布局可控三项前提才能用SharedArrayBuffer和Atomics构建高性能跨线程模型;否则将引发静默数据错乱或TypeError。
不能直接用 SharedArrayBuffer 和 Atomics 构建“极致性能”的跨线程协作模型——除非你已满足跨域隔离、正确同步、内存布局可控这三项硬性前提。跳过任一环节,性能不会提升,只会引入静默数据错乱或 TypeError: SharedArrayBuffer is not defined。
浏览器控制台报 SharedArrayBuffer is not defined 或 Atomics is not defined,不是代码写错了,而是环境没达标:
Cross-Origin-Opener-Policy: same-origin 和 Cross-Origin-Embedder-Policy: require-corp
<script>、<iframe>、<link rel="stylesheet"> 等所有跨源资源加载标签需显式加 crossorigin 属性(哪怕同域)file:// 协议被禁用),必须走 localhost 或 127.0.0.1,例如 npx serve -p 8080
Atomics.wait()
Atomics.wait() 的行为常被误解为“让当前线程休眠 N 毫秒”,实际它只做一件事:在指定 Int32Array 索引位置的值**等于预期值**时,挂起当前线程,直到另一线程调用 Atomics.notify() 唤醒它。它不接受毫秒参数,也不保证唤醒时间。
Atomics.wait(view, 0, view[0], 1000) —— 第四个参数在多数浏览器中被忽略,且若 view[0] 已变,该调用立即返回 "not-equal",根本不会等view[0] = 1 → Worker 检查 Atomics.load(view, 0) === 1 → 调用 Atomics.wait(view, 0, 1) → 主线程后续调用 Atomics.notify(view, 0, 1) 唤醒notify 配合的场景下单独使用 wait,否则线程永久挂起,无法 debug以下两段代码执行 10000 次递增,在 4 个 Worker 并发下结果几乎必然不是 40000:
// ❌ 错误:非原子读-改-写int32View[0] = int32View[0] + 1;// ✅ 正确:单条原子指令完成Atomics.add(int32View, 0, 1);
Atomics.add() 是 CPU 级原子指令映射,不可中断;类似地,Atomics.compareExchange() 适合实现自旋锁Atomics.load(view, i) 而非 view[i],确保看到的是最新写入值(避免 CPU 缓存不一致)在 WASM 场景下,SharedArrayBuffer 的使用路径和 JS Worker 不同,容易混淆:
-pthread -s USE_PTHREADS=1,否则生成的 WASM 模块根本不识别共享内存(memory (shared 1 10)),即初始 1 页(64KB)、最大 10 页,且带 shared 标识SharedArrayBuffer 对象本身,而是通过 Module._malloc() 分配的指针地址,由 WASM 自行映射到共享内存段__atomic_add_fetch 等内置函数,最终编译为对 Atomics.add 的调用,开发者无需手写 JS 层原子操作最易被忽略的一点:共享内存没有自动垃圾回收机制。一旦创建 SharedArrayBuffer,它会一直驻留直到所有引用(包括 Worker 中的视图)全部释放。Worker 未正确 terminate() 或视图未置空,会导致内存泄漏,且无法被常规 DevTools 检测到。