Atomics.waitAsync只能在Worker线程调用,主线程调用会抛TypeError;需通过主线程创建SharedArrayBuffer并传递给Worker,各Worker用同一buffer构造Int32Array;waitAsync返回Promise表示注册成功,resolve不保证等到,须配合Atomics.load检查初值并处理notify唤醒;主线程应由Worker主动postMessage通知,不可轮询或等待。

Atomics.waitAsync 为什么不能直接在主线程用
Atomics.waitAsync 是一个底层原子操作,设计上只允许在 Worker 线程中调用。主线程调用会立刻抛出 TypeError: Atomics.waitAsync is not supported in this context。这不是兼容性问题,而是规范强制限制——它依赖线程级的等待队列和事件循环调度机制,主线程没有该能力。所以“跨 Worker 异步通知”这个目标,天然要求信号发起方和接收方都在 Worker 中,主线程只能作为协调者或 UI 更新入口。
如何构造共享的 Int32Array 和 SharedArrayBuffer
必须确保所有参与通信的 Worker 使用同一块 SharedArrayBuffer,且通过同一段初始化逻辑获取指向同一内存区域的 Int32Array。常见错误是每个 Worker 自己 new 一个 SharedArrayBuffer,导致看似同名变量实则互不感知。
推荐做法:
- 主线程创建
SharedArrayBuffer(例如new SharedArrayBuffer(4)),并封装成Int32Array后通过postMessage(..., [buffer])传给各 Worker - Worker 收到后,用相同字节偏移构造视图:
const signal = new Int32Array(sharedBuf, 0, 1) - 务必初始化值,比如
signal[0] = 0,否则读写行为未定义 - 不要复用已有数组(如从
ArrayBuffer转来),必须来自SharedArrayBuffer
waitAsync 的正确调用模式与 Promise 生命周期
Atomics.waitAsync 返回一个 Promise,但它的 resolve 并不表示“等到了”,而是“注册成功并开始监听”。真正触发 resolve 的是另一个线程对同一位置执行 Atomics.notify。如果调用时当前值已满足等待条件(即等于预期值),Promise 会立即 resolve,但不会自动重试 —— 这是容易忽略的关键点。
典型安全用法:
- 先用
Atomics.load(signal)检查当前值,若已是目标态,直接跳过 wait;否则再调用waitAsync(signal, expectedValue, timeoutMs) -
timeoutMs是可选参数,设为0表示无限等待;设为正数时超时后 Promise reject,错误类型为DOMException,name === "TimeoutError" - Promise resolve 后返回对象形如
{ async: true, value: "ok" }或{ async: false, value: "not-equal" },需判断value字段而非仅看是否 resolve - 一次
notify最多唤醒一个等待者(FIFO),如需广播,得多次调用或配合计数器
主线程如何安全响应 Worker 发来的信号
主线程本身不能调用 waitAsync,但可以接收 Worker 主动发来的消息。Worker 在 waitAsync resolve 后应立刻 postMessage 通知主线程,而不是试图让主线程“等”。这是解耦关键。
示例流程:
- Worker A 执行
Atomics.waitAsync(signal, 0)→ 等待 signal 变为 0 - Worker B 执行
Atomics.store(signal, 0); Atomics.notify(signal, 1)→ 写值 + 唤醒最多 1 个等待者 - Worker A 的 Promise resolve 后,执行
self.postMessage({ type: "signal_received" }) - 主线程监听
worker.onmessage,收到后更新 UI 或触发后续逻辑
注意:不要在主线程里轮询 Atomics.load,那会空转 CPU;也不要让 Worker 长时间 hold 消息而不 post,否则信号丢失无感知。
真正难的是状态同步粒度和竞态控制——比如多个 Worker 同时 wait 同一地址,notify 数量没配对,或者主线程收到消息后又误发重复指令。这些细节不写进共享内存协议里,光靠 waitAsync 无法兜底。


















