在 javascript 模块中使用 async 和 await,只需将函数声明为 async,并在其中使用 await 等待异步操作完成即可。对于 es 模块(.mjs)或配置了 type: module 的 .js 文件,顶层作用域可以直接使用 await;而在 commonjs 模块中,由于不支持顶层 await,必须将逻辑包裹在 async 函数内部并调用该函数。

ES 模块中顶层 await 的使用条件与限制
在支持顶层 await 的环境中,可以直接在模块顶部等待一个 Promise,这简化了初始化逻辑。但需注意,顶层 await 会使当前模块变为“动态依赖”,即其他导入该模块的代码必须等待其解析完成,且顶层 await 不能用于脚本标签(<script></script>)加载的模块,仅适用于通过 import 语句引入的模块。

const data = await fetch('https://api.example.com/data').then(r => r.json());
console.log(data); // 确保数据已加载
export const processData = () => data.map(item => item.id);
上述代码展示了在 ES 模块中直接使用顶层 await 获取远程数据并导出的场景。运行此模块时,Node.js 或现代浏览器会暂停模块执行直到 fetch 完成,随后导出处理函数。若在其他模块中 import 此模块,导入操作也会阻塞,直到本模块完全就绪。
CommonJS 模块中封装异步初始化的方法
CommonJS 模块不支持顶层 await,因此需要将异步逻辑封装在立即执行的 async 函数中。这种方式允许在模块加载阶段完成异步初始化,同时保持模块结构的兼容性。需要注意的是,这种模式下的异步初始化是模块级别的,所有导入该模块的代码都会共享同一份初始化结果。
Java开发手册规约集合,基于阿里巴巴Java开发手册(嵩山版)。 涵盖7大维度:编程规约、异常日志、单元测试、安全规约、MySQL数据库、工程结构、设计规约。

let cachedData;
(async () => {
const response = await fetch('https://api.example.com/config');
cachedData = await response.json();
})();
module.exports = { getCachedData: () => cachedData };
这段代码演示了在 CommonJS 模块中如何通过 IIFE(立即调用函数表达式)包装 async 函数来实现异步初始化。虽然模块导出同步发生,但实际数据会在后台加载完成后填充 cachedData。调用者需意识到返回值可能暂时为 undefined,除非提供额外的状态检查机制。
顶层 await 对模块依赖链的影响
当模块 A 使用顶层 await 时,任何导入模块 A 的模块 B 都必须等待模块 A 的异步操作完成才能继续执行。这意味着模块依赖链中的每个环节都可能因异步操作而延迟。在实际应用中,应尽量避免在核心依赖路径上使用顶层 await,以免引发启动性能问题或死锁风险。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










