顶级 await 仅适用于 ES 模块,需通过 type="module"、.mjs 后缀或 package.json 中 "type": "module" 启用;它允许模块顶层直接 await,按序串行执行,阻塞导入者,错误须在模块内 try/catch 捕获。

顶级 await 只能在 ES 模块(ESM)中使用,不能在 CommonJS 或脚本(<script></script>)环境中直接使用;它允许在模块顶层直接写 await 表达式,而无需包裹在 async 函数内。
必须在 ESM 模块上下文中启用
顶级 await 依赖模块的异步初始化语义。只有当模块以 type="module" 加载,或文件后缀为 .mjs(或被 package.json 中 "type": "module" 标识),才能被 JavaScript 引擎识别为 ESM 模块并启用顶级 await。
- 浏览器中需用
<script type="module"></script>引入 - Node.js 中需满足以下任一条件:
.mjs后缀、package.json含"type": "module"、或通过node --input-type=module执行字符串代码 - 若用
require()加载或node index.js(且未启用模块模式),会报错SyntaxError: await is only valid in async functions and the top level bodies of modules
模块执行顺序受 await 影响
含顶级 await 的模块会暂停自身执行,等待 Promise 解决后才继续,并阻塞其所有静态导入者(即依赖它的模块)。这改变了传统模块同步加载的时序模型。
- 假设模块 A
import模块 B,而 B 有顶级await fetch(...),则 A 的执行会等到 B 的 Promise 完成后才开始 - 多个顶级 await 会按书写顺序串行执行,但不会自动并行(如需并发,应显式用
Promise.all()) - 注意:模块缓存仍生效——同一模块多次 import 不会重复执行顶级代码,包括 await 部分
不能用于动态 import() 的返回值解构
顶级 await 作用于表达式,而非声明。虽然可 await import('./foo.js'),但不能在顶层直接解构其默认导出或命名导出:
- ✅ 合法:
const mod = await import('./utils.js'); - ❌ 非法:
const { helper } = await import('./utils.js');(解构不是简单赋值,属于声明语句) - ✅ 替代写法:
const mod = await import('./utils.js'); const { helper } = mod;
错误处理需显式捕获
顶级 await 抛出的异常会导致整个模块实例化失败,且无法被外部 try/catch 捕获(因 import 是声明式行为)。必须在模块内部用 try...catch 处理。
- 例如:
try { const data = await fetch('/api').then(r => r.json()); } catch (e) { console.error('初始化失败', e); } - 若未捕获,模块状态变为
"errored",所有依赖它的import语句都会拒绝 Promise,抛出异常 - Node.js 中可通过
process.on('unhandledRejection')监听,但不推荐作为兜底方案
不复杂但容易忽略:它让模块具备“异步初始化”能力,但也要求开发者更谨慎地设计依赖链和错误恢复逻辑。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











