async/await 必须在 async 函数内使用,顶层 script 中直接 await 会报语法错误;async 函数返回 Promise,需 await 或 then 处理;await 仅解包 Promise,不等待 DOM 或事件;并发请求应优先用 Promise.all 而非连续 await。

async/await 不能直接写在 HTML 的 <script> 标签顶层,必须包裹在 async 函数内;否则会报 SyntaxError: await is only valid in async functions。
为什么 await 在 script 标签里直接用就报错
浏览器解析脚本时,await 只被允许出现在 async 函数作用域中。HTML 中的内联 <script> 或外部 JS 文件都遵循这一规则——它不是“环境限制”,而是 JavaScript 语言规范强制要求。
-
await fetch('/api')单独写在<script>里 → 报错,因为没函数包裹 -
function foo() { await fetch(); }→ 报错,缺async修饰 -
const foo = async () => await fetch();→ 合法,箭头函数也需显式加async -
<script type="module">里仍不支持顶层await(注意:这和 Node.js 的顶层await不同)
async 函数返回值永远是 Promise
哪怕你 return 123 或 return null,async 函数也会自动包装成 Promise.resolve(123)。这意味着调用它必须用 .then() 或再次 await,不能当普通同步函数用。
-
async function f() { return 'ok'; }→f()返回Promise {<resolved>: "ok"} - 忘记
await f()或f().then(...),后续逻辑就拿不到值 - 错误地写成
const x = f(); console.log(x.data)→x是 Promise,没有data属性,会得undefined
常见误用:把 await 当“等 DOM 加载”或“等事件”
await 只解包 Promise,对 DOM 节点、事件监听器、定时器本身无等待能力。它不会让代码“停在那儿等按钮被点”。
立即学习“前端免费学习笔记(深入)”;
-
await document.getElementById('btn')→ 立即执行,返回null或元素,不是“等它出现” - 想等 DOM 就绪?用
document.addEventListener('DOMContentLoaded', ...)或<script defer> - 想等用户点击?必须写在事件回调里:
btn.addEventListener('click', async () => { await apiCall(); }) -
await setTimeout(...)无效——setTimeout返回的是 timer ID(数字),不是 Promise;要封装:await new Promise(r => setTimeout(r, 1000))
串行 vs 并行:别让可并发的请求变慢
连续写多个 await 是串行执行,每个请求必须等前一个结束才发下一个。但多数 API 请求互不依赖,应并行发起以节省总耗时。
- 串行(慢):
const a = await fetch('/a'); const b = await fetch('/b');→ 至少耗时a + b - 并行(快):
const [a, b] = await Promise.all([fetch('/a'), fetch('/b')]);→ 耗时接近max(a, b) - 混合场景:先取 token,再用 token 并行取数据 → 第一个
await,后面用Promise.all - 错误假设“
await更安全所以全用它” → 实际可能拖慢页面加载和交互响应
真正容易被忽略的是微任务调度细节:await 后续代码和 Promise.then() 都进微任务队列,但顺序不严格等价;如果 UI 更新或状态依赖执行先后,别靠直觉猜,用 Promise.resolve().then() 显式对齐,或拆成明确的步骤控制流。



















