HTML5通过Web Workers实现并发,默认不共享内存,天然避免Data Race;真正风险在于SharedArrayBuffer未配合Atomics使用,或业务逻辑层的伪竞态。

HTML5 本身不支持传统意义上的多线程(如 Java 或 C++ 的共享内存线程),它通过 Web Workers 实现并发,而 Web Workers 之间**默认不共享内存**,因此天然规避了典型 Data Race(数据竞争)问题。关键在于:竞态条件不是“如何防止”,而是“如何在设计中避免引入共享状态的错觉”。
理解 Web Workers 的通信本质:消息传递而非共享内存
Worker 与主线程、Worker 与 Worker 之间只能通过 postMessage() 和 onmessage 交换**结构化克隆后的数据副本**(如对象、数组、ArrayBuffer 等),原始引用被切断。这意味着:
- 你无法在两个上下文中同时读写同一个 JavaScript 对象属性;
- 修改 Worker 内的对象,不会影响主线程中的同名变量;
- 看似“共享”的 ArrayBuffer 可通过
transferable机制实现零拷贝移交——但移交后,原上下文立即失去访问权,不存在同时读写。
真正需防范的“伪竞态”场景
虽然无共享堆内存,但在业务逻辑层仍可能出现逻辑竞态,例如:
- 多个 Worker 并发请求同一后端接口,未加请求去重或节流,导致重复提交;
- 主线程与 Worker 都维护同一份 UI 状态缓存(如本地搜索结果),各自更新却不同步;
- 使用 SharedArrayBuffer(需 HTTPS + Cross-Origin-Isolated)时,若未配合 Atomics 操作,直接读写同一索引位置。
其中,SharedArrayBuffer 是 HTML5 中唯一可能触发真实 Data Race 的机制,但它属于可选高级特性,且启用门槛高(需服务端设置 Cross-Origin-Opener-Policy 和 Cross-Origin-Embedder-Policy)。
立即学习“前端免费学习笔记(深入)”;
安全使用 SharedArrayBuffer 的必要实践
若确需低延迟共享内存(如音视频处理、游戏物理模拟),必须:
- 始终用
Atomics.wait()/Atomics.notify()协调等待与唤醒; - 对复合操作(如“读-改-写”)使用
Atomics.compareExchange()或Atomics.add()等原子操作,不可拆分为多次非原子访问; - 避免在 SharedArrayBuffer 上存放 JavaScript 对象引用(只存数字、布尔等基本类型);
- 明确划分内存区域职责(如 Worker A 写 offset 0–1023,Worker B 写 1024–2047),减少临界区。
更推荐的健壮设计模式
绝大多数场景下,应优先采用无共享架构:
- 将状态单一源头(Single Source of Truth)保留在主线程,Worker 仅接收任务、返回结果;
- 对耗时计算,使用
OffscreenCanvas+ Worker 处理图像,结果通过transferToImageBitmap()零拷贝提交; - 用
MessageChannel创建专用通道,隔离不同 Worker 的通信,避免事件监听器混乱; - 复杂协作逻辑(如多人协同编辑)交由服务端做最终一致性仲裁,前端只做乐观更新与冲突回滚。


















