Atomics.waitAsync 主线程等待共享内存通知的实现方式与超时边界
如果页面需要等待共享内存中的状态变化,Atomics.waitAsync() 的关键价值是“等待期间不阻塞整条主线程”。它只能接收指向 SharedArrayBuffer 的 Int32Array 或 BigInt64Array,返回值还分成同步字符串和异步 Promise 两种形态:初始值不匹配时立即得到 not-equal,零超时可能立即得到 timed-out,真正进入等待后再由 Promise 得到 ok 或 timed-out。
官方资料地址:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics/waitAsync
先把返回对象拆开:async 决定是否等待
Atomics.waitAsync(view, index, expected, timeout) 返回一个对象,而不是直接返回 Promise。先看 async,再处理 value,可以避免把同步字符串误当成 Promise。
| 状态 | 典型返回 | 含义 |
|---|---|---|
| 值已变化 | { async: false, value: "not-equal" } | 不用等待,当前值已经不是 expected |
| 零超时 | { async: false, value: "timed-out" } | 只做一次即时检查 |
| 进入等待 | { async: true, value: Promise } | 等待通知或超时,Promise 最终为 ok 或 timed-out |

用共享整数建立一个主线程等待点
下面的例子用一个共享整数表示“是否就绪”。主线程调用等待后仍能处理定时器和界面事件;示例中的定时器只模拟另一个执行者写入状态并通知等待者。
// main.js:用共享整数表示 ready 状态,0 表示未就绪,1 表示已就绪
const shared = new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT);
const state = new Int32Array(shared);
async function waitUntilReady(timeout = 1000) {
// 第三个参数是期望值;若它已变化,方法会立即返回 not-equal
const result = Atomics.waitAsync(state, 0, 0, timeout);
// value 可能是字符串,也可能是 Promise,统一转换后再处理结果
return result.async ? await result.value : result.value;
}
waitUntilReady().then((status) => {
// ok 表示收到通知,timed-out 表示在期限内没有收到通知
console.log("共享状态等待结果:", status);
});
setTimeout(() => {
// 先写入新状态,再通知等待者,减少读到旧状态的竞态
Atomics.store(state, 0, 1);
Atomics.notify(state, 0, 1);
}, 100);
这个示例的可复用边界有三点:视图必须指向共享内存,等待位置必须在数组范围内,写入方要先完成 Atomics.store 再执行 Atomics.notify。如果调用方本来就把位置改成了 1,等待函数不会再挂起,而是直接返回 not-equal。
超时和通知竞态要按结果处理
超时不是异常。异步等待的 Promise 会以字符串完成,不会因为等不到通知而自动 reject,所以业务代码应显式分支。通知也不是“把值改好”的动作,真正改变共享状态的是写入操作;只调用 Atomics.notify 而不更新值,下一次检查仍可能看到旧状态。
// 只等待一次:把超时当作正常业务分支,不制造未处理拒绝
const result = Atomics.waitAsync(state, 0, 0, 250);
const status = result.async ? await result.value : result.value;
if (status === "ok") {
// 收到通知后仍应读取共享值,确认状态确实满足业务条件
const ready = Atomics.load(state, 0) === 1;
console.log("收到通知,ready=", ready);
} else if (status === "timed-out") {
// 超时只说明本轮没有等到通知,不等于共享数据损坏
console.log("等待超时,保留重试或降级路径");
} else {
// not-equal 表示调用前状态已经变化,可直接进入检查流程
console.log("状态已提前变化:", status);
}

兼容性与降级:不要把新 API 当成唯一通道
使用前先做能力检测,并把共享内存的安全上下文限制纳入部署检查。浏览器不支持 Atomics.waitAsync,或页面无法获得可用的 SharedArrayBuffer 时,可以退回 Worker 消息、普通事件或轮询任务;降级方案虽然没有共享内存的同步语义,但更容易覆盖旧环境。
// 先检测 API 和共享内存构造能力,再选择等待实现
function canUseWaitAsync() {
try {
return typeof Atomics.waitAsync === "function" &&
typeof SharedArrayBuffer === "function";
} catch (error) {
// 某些受限环境访问构造器会失败,交给上层走消息降级
return false;
}
}
if (!canUseWaitAsync()) {
// 这里应接入 Worker.postMessage、事件或业务已有的异步通知机制
console.log("使用普通异步通知降级");
}
- 需要主线程继续响应交互时,优先使用
waitAsync,不要用会阻塞线程的同步等待。 - 看到
not-equal先读取当前共享值,不要把它记录成超时。 - 发布前用目标浏览器做特性检测;安全上下文或跨源隔离条件不满足时,保留消息型降级。
常见问题
Atomics.waitAsync 和 Atomics.wait 最大的区别是什么?
Atomics.wait 会同步等待,而 waitAsync 返回可等待的 Promise,不会把主线程整个卡住。两者都依赖共享内存视图和正确的通知顺序。
为什么 timeout 设为 0 时没有 Promise?
零超时只做即时比较,不进入等待队列,因此可以直接返回 timed-out 或 not-equal。代码应先判断 result.async,不要无条件调用 result.value.then()。
File System Access API 的 write、seek 和 truncate 有什么区别
- 上一篇
- File System Access API 的 write、seek 和 truncate 有什么区别
- 下一篇
- URLPattern前端路由匹配怎样减少手写正则怎样完成一个可复用的最小示例
-
- 文章 · 前端 | 31分钟前 |
- File System Access API 的 write、seek 和 truncate 有什么区别
- 400浏览 收藏
-
- 文章 · 前端 | 35分钟前 | 前端 · 性能 · javascript · ReadableStream Web Streams highWaterMark desiredSize backpressure 前端流式读取
- Web Streams backpressure前端流式读取怎样避免消费速度失控为什么结果为空或不符合预期
- 239浏览 收藏
-
- 文章 · 前端 | 38分钟前 |
- Web Streams backpressure前端流式读取怎样避免消费速度失控怎样完成一个可复用的最小示例
- 183浏览 收藏
-
- 文章 · 前端 | 42分钟前 |
- CSS Subgrid嵌套卡片怎样沿用父网格的列宽怎样在批处理代码中减少额外分配
- 157浏览 收藏
-
- 文章 · 前端 | 43分钟前 |
- CSS Subgrid嵌套卡片怎样沿用父网格的列宽为什么结果为空或不符合预期
- 489浏览 收藏
-
- 文章 · 前端 | 45分钟前 | 前端开发 · 列宽对齐 CSS Grid 前端布局 CSS subgrid 嵌套卡片
- CSS Subgrid嵌套卡片怎样沿用父网格的列宽怎样完成一个可复用的最小示例
- 157浏览 收藏
-
- 文章 · 前端 | 1天前 | 前端 · Web APIs Permissions Policy iframe allow
- Web APIs 怎样排查权限策略阻止的功能
- 110浏览 收藏
-
- 文章 · 前端 | 1天前 |
- Service Worker 怎样区分缓存优先和网络优先
- 320浏览 收藏
-
- 文章 · 前端 | 1天前 | javascript · css · View Transition API view-transition-name Element.startViewTransition
- View Transition API 怎样只过渡局部元素
- 409浏览 收藏
-
- 文章 · 前端 | 1天前 | javascript · IndexedDB 对象仓库迁移 upgradeneeded
- IndexedDB 怎样迁移对象仓库结构
- 303浏览 收藏
-
- 文章 · 前端 | 1天前 | javascript · JavaScript Element.checkVisibility DOM可见性
- Element.checkVisibility() 怎样判断元素是否真正可见
- 293浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 955次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 960次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 1071次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 1045次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 879次使用
-
- Go语言对前端领域的入侵WebAssembly运行原理
- 2022-12-31 130浏览
-
- Go Goja 怎么预编译脚本并在多个运行时执行
- 2026-10-13 306浏览
-
- 这样需求的表单一般要这么做?
- 2023-02-17 194浏览
-
- go+gin 静态资源路由与后端api路由冲突如何解决?
- 2023-02-24 414浏览
-
- css 中的px 跟 video 中px 等同吗?
- 2023-01-09 427浏览

