async/await是Promise语法糖,不改变事件循环机制;await仅暂停当前async函数执行,不阻塞主线程;必须在async函数内使用;返回值总是Promise;错误需用try/catch捕获;并发需用Promise.all等主动实现。

async/await 本质上是 Promise 的语法糖,不是新异步机制
它没有改变 JavaScript 异步的底层模型(仍是基于微任务、事件循环),只是让基于 Promise 的异步流程写起来更像同步代码。你写 await fetch('/api'),实际等价于 fetch('/api').then(...),只是引擎自动帮你展开和错误捕获了。
常见误解是“用了 await 就能阻塞线程”——完全错误。await 只是暂停当前 async 函数的执行,把控制权交还给事件循环,不会阻塞主线程或其它任务。
await 必须在 async 函数内使用,否则 SyntaxError
直接写 await Promise.resolve(42) 在顶层或普通函数里会报 SyntaxError: await is only valid in async function。这是硬性语法规则,不是运行时限制。
- 顶层 await 只在 ES2022+ 模块中可用(如
type="module"的 script 或 Node.js 的 .mjs 文件),普通脚本仍不支持 -
async函数返回值总是 Promise:即使你return 123,实际返回的是Promise.resolve(123) - 想在非 async 环境“用 await”,只能包一层:
(async () => { const data = await api(); })()
错误处理必须用 try/catch,不能只靠 .catch()
await 把 Promise rejection 转成同步抛出的异常,所以 .catch() 无法捕获它——除非你在 await 后链式调用,但那就失去 await 的意义了。
立即学习“Java免费学习笔记(深入)”;
正确写法:
async function loadData() {
try {
const res = await fetch('/api');
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return await res.json();
} catch (err) {
console.error('加载失败:', err.message);
throw err;
}
}
漏掉 try/catch 是最常导致未捕获异常崩溃的原因;尤其注意 await 后面的表达式本身也可能同步抛错(比如 await null.then())。
并发请求别盲目 await,小心变成串行
写成这样就错了:
const a = await fetch('/a');
const b = await fetch('/b'); // 等 a 完了才发 b
实际想并发,得先发起所有 Promise,再统一 await:
const [a, b] = await Promise.all([
fetch('/a'),
fetch('/b')
]);
-
Promise.allSettled更适合容错场景(部分失败也要继续) - 大量并发时注意浏览器连接数限制(通常 6 个同域),
Promise.all失败会短路,allSettled不会 - 想控制并发数量(比如同时最多 3 个请求),得手写批处理逻辑,不能只靠 await
很多人以为 “用了 async/await 就天然支持并发”,其实恰恰相反——它默认倾向串行,需要主动打破。











