await 只能在 async 函数内部或 es 模块顶层使用,否则抛出 syntaxerror;async 函数提供挂起/恢复上下文,使 await 能注册微任务并自动包装返回值为 promise。

没错,await 只能在 async 函数内部使用,这是 JavaScript 的硬性语法规则,不是建议,而是引擎强制执行的限制。一旦违反,直接抛出 SyntaxError: await is only valid in async function,代码根本无法解析运行。
为什么必须在 async 函数里用 await
async 函数提供了一个特殊的执行上下文,让引擎知道:“这段代码可能中途暂停、需要恢复”。await 本身不暂停线程,而是把后续逻辑注册为微任务,等 Promise settle 后再继续执行——这个挂起和恢复机制,只有 async 函数能支持。
- 普通函数没有这种上下文,引擎遇到 await 就不知道怎么处理,只能报错
- 即使函数里只有一行 await,也必须显式声明为 async;不能靠“写了 await 就自动变异步”
- async 不仅是为 await 而存在,它还会自动把返回值包装成 Promise,这是配套行为
哪些写法会触发语法错误
以下所有情况都会在解析阶段失败,根本不会进入执行:
- 在普通函数声明/表达式里写 await:
function foo() { await fetch('/api'); } - 在箭头函数里直接写 await:
const fn = () => { await fetch('/api'); }; - 在立即执行函数(IIFE)中用同步函数包装:
(function(){ await Promise.resolve(); })(); - 在模块顶层以外的普通脚本中直接写 await(ES 模块顶层除外)
合法的使用场景
真正能用 await 的地方其实就两类:
-
async 函数内部:包括普通函数、箭头函数、方法定义,只要带 async 前缀就行
例如:async function getData() { return await fetch('/api').then(r => r.json()); } -
ES 模块的顶层作用域:在
<script type="module"></script>或 .mjs 文件中,可直接写await fetch(...)
常见误解与实际效果
很多人以为 await 是“让代码停一下”,但它的行为更精细:
- await 123 或 await 'hello' 是合法的,因为 JS 会自动用
Promise.resolve()包装,但不会产生真实等待——下一行代码会在当前宏任务结束后、微任务队列里执行 - 真正起作用的 await,必须等一个“真异步操作”完成,比如
fetch()、setTimeout(() => {}, 1000)返回的 Promise - 多个 await 是串行的:前一个 Promise resolve 后,才开始下一个,不是并发发起
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











