无需登录 数据私有 本地保存

顶级 await 演示 - 在模块顶层使用异步

7
0
0
0

顶级 await 演示

ES2022 新特性 — 在模块顶层直接使用 await,无需包裹在 async 函数中

ES2022 Module Script 浏览器支持 Node.js 14.8+
数据获取 配置加载 动态导入 并行请求 错误处理
📄 module.js type="module"

            
点击查看「传统方式」对比
📄 old-style.js — 传统 async 函数包裹方式

            
控制台输出
点击「运行」执行代码
就绪
无需 async 包装

在模块顶层直接使用 await,代码更简洁直观,减少嵌套层级。

阻塞模块执行

顶级 await 会阻塞依赖该模块的其他模块加载,需谨慎使用。

仅限 ES Module

仅在 type="module".mjs 文件中可用,普通 script 不支持。

常见问题 FAQ

顶级 await(Top-Level Await)是 ES2022 引入的特性,允许开发者在 ES 模块的顶层作用域直接使用 await 关键字,而无需将其包裹在 async 函数内。它解决了模块初始化时需要异步获取数据的问题——例如加载配置、初始化数据库连接、获取国际化翻译等场景,让模块代码更加简洁自然。

浏览器端需要 <script type="module"> 标签或使用 .mjs 扩展名。Node.js 从 v14.8 开始支持顶级 await(需使用 ES Module 模式)。主流现代浏览器(Chrome 89+、Firefox 89+、Safari 15+、Edge 89+)均已支持。注意:CommonJS 模块和普通 <script> 标签不支持顶级 await。

会的。如果一个模块使用了顶级 await,那么所有直接或间接依赖该模块的其他模块都会等待其执行完成。这是顶级 await 的一个重要特性,也是一把双刃剑——它确保了依赖模块获得的是已经完全初始化的数据,但也可能导致加载延迟。建议仅在确实需要的入口模块或关键配置模块中使用。

本质上是相同的——都暂停当前执行上下文直到 Promise 完成。区别在于作用域:async 函数内的 await 只影响该函数,而顶级 await 影响的是整个模块的执行。此外,顶级 await 的结果可以直接被模块内所有代码使用,而 async 函数的结果需要通过返回值或闭包传递。

可以直接在顶层使用 try...catch 包裹 await 表达式。如果顶级 await 的 Promise 被拒绝且未被捕获,会导致模块加载失败(类似于 import 失败)。因此建议始终对可能失败的顶级 await 做好错误处理,提供降级方案或合理的错误提示。

常见场景包括:① 加载应用配置(如从 API 获取配置后再初始化应用);② 国际化翻译加载(根据用户语言动态导入翻译文件);③ 数据库连接初始化(确保连接就绪后再导出模块);④ 条件性动态导入(根据运行时条件加载不同模块);⑤ 资源预加载(在模块加载时并行获取多个资源)。

普通 <script> 标签是同步执行的,浏览器期望它们立即完成。如果允许顶级 await,会打乱脚本的执行顺序,导致依赖关系难以管理。ES Module(type="module")天然支持异步加载和明确的依赖图,因此可以安全地支持顶级 await。

顶级 await 会延迟模块的完成时间,可能影响页面中依赖该模块的渲染。如果模块负责首屏关键内容,过长的 await 时间会推迟内容呈现。建议:① 控制 await 的超时时间② 对非关键模块避免使用顶级 await③ 使用 SSR/预渲染来缓解对 SEO 的影响。合理使用下,其影响通常是可控的。

完全可以。在模块顶层使用 await Promise.all([...]) 是非常推荐的模式。这样可以并行发起多个异步请求,然后统一等待所有结果,比串行 await 效率高得多。这是顶级 await 在实际项目中非常实用的用法。

可以尝试使用 new Function('await Promise.resolve()') 检测,但更简单的做法是检查浏览器版本或使用构建工具(如 Webpack、Vite、Rollup)进行语法转换。大多数现代打包工具已经支持将顶级 await 编译为兼容代码。在生产环境中,建议依赖工具链而非手动检测。