当前位置:首页 > 文章列表 > 文章 > 前端 > Atomics.waitAsync 主线程等待共享内存通知的实现方式与超时边界

Atomics.waitAsync 主线程等待共享内存通知的实现方式与超时边界

来源:17golang原创 2026-11-09 11:36:50 0浏览 收藏

如果页面需要等待共享内存中的状态变化,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
Atomics.waitAsync 返回对象中 async 与 value 两条结果路径的静态结构说明图
图1:Atomics.waitAsync 返回值说明图,展示同步字符串、异步 Promise 与最终状态的关系;这不是运行截图。

用共享整数建立一个主线程等待点

下面的例子用一个共享整数表示“是否就绪”。主线程调用等待后仍能处理定时器和界面事件;示例中的定时器只模拟另一个执行者写入状态并通知等待者。

// 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);
}
Atomics.store、Atomics.notify、等待结果和超时分支之间的静态边界说明图
图2:通知与超时边界说明图,强调先写共享值、再通知,以及 ok、timed-out、not-equal 三种结果的处理关系;这不是运行截图。

兼容性与降级:不要把新 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()。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
File System Access API 的 write、seek 和 truncate 有什么区别File System Access API 的 write、seek 和 truncate 有什么区别
上一篇
File System Access API 的 write、seek 和 truncate 有什么区别
URLPattern前端路由匹配怎样减少手写正则怎样完成一个可复用的最小示例
下一篇
URLPattern前端路由匹配怎样减少手写正则怎样完成一个可复用的最小示例
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    955次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    960次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    1071次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    1045次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    879次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码