Web Worker 默认安全,因不共享内存且通过结构化克隆传递数据;伪竞态源于业务逻辑冲突,真数据竞争仅出现在 SharedArrayBuffer 未配合 Atomics 使用时。

Web Worker 本身不引发传统多线程中的竞态条件,因为它不共享内存;真正需要预防的,是开发者误以为“能共享”而引入的逻辑冲突或对 SharedArrayBuffer 的非原子操作。
Worker 默认就是安全的:靠消息传递隔离状态
主线程和每个 Worker 都有独立的 JavaScript 执行上下文、堆内存和事件循环。它们之间只能通过 postMessage() 和 onmessage 交换数据,而这些数据是结构化克隆后的副本——对象被深拷贝,引用关系完全断开。
- 你在 Worker 里改
data.count++,主线程里的同名变量不会变; - 传入一个数组,Worker 内部
push新元素,不影响主线程原始数组; - 即使传
ArrayBuffer,默认也是拷贝;若用transferable移交,则原上下文立刻失去访问权,不存在“双方同时读写”。
伪竞态最常出现在业务逻辑层
没有共享内存,但可能有共享意图。比如多个 Worker 同时调用同一个 API 接口,或主线程与 Worker 各自维护一份本地搜索缓存,更新不同步。
- 并发请求未加去重或节流 → 重复提交、库存超扣;
- UI 状态(如 loading 标志、搜索结果)在两个线程中分别管理 → 状态错乱、界面闪烁;
- 用
setTimeout或setInterval在 Worker 中轮询,又没做防重入 → 多次触发同一处理逻辑。
只有 SharedArrayBuffer 才真有 Data Race 风险
这是 HTML5 中唯一允许跨 Worker 直接读写同一内存区域的机制,但启用门槛高(需 HTTPS + Cross-Origin-Isolated),且必须配合 Atomics 使用,否则就是裸奔。
- 直接对
sharedArray[0] = 1赋值 → 不安全,可能被覆盖; - 读-改-写操作必须用
Atomics.compareExchange()或Atomics.add(); - 等待/通知必须用
Atomics.wait()和Atomics.notify(),不能靠轮询或普通变量; - 内存区域最好划分职责,避免多个 Worker 写同一段偏移地址。
实用建议:从设计上绕开问题
多数场景根本不需要 SharedArrayBuffer。优先采用更简单、更健壮的方式:
- 把计算任务拆成独立单元,由主线程统一分配、Worker 各自处理、结果汇总;
- 状态变更统一走主线程,Worker 只负责“算”,不负责“管”;
- 缓存类数据,让 Worker 返回完整结果,主线程决定是否更新 UI 或本地存储;
- 真要用共享内存,先确认是否满足隔离策略,再封装一层带原子操作的工具函数,别裸用
Int32Array。


















