async函数一定返回Promise对象——即使return 42也会被包装为Promise.resolve(42),不写return则等价于return Promise.resolve(undefined);await只能在async函数内使用,因其暂停机制依赖async标记的异步上下文。

async 和 await 是 JavaScript 中处理异步操作的语法糖,本质是基于 Promise 的封装。它们不改变异步本质,但让代码写起来像同步一样线性、可读、易调试。
async 函数返回什么?为什么必须用它包裹 await?
async 函数一定返回一个 Promise 对象——哪怕你 return 42,它也会被自动包装成 Promise.resolve(42);如果你没写 return,就等价于 return Promise.resolve(undefined)。
await 只能在 async 函数内部使用,因为它的作用是“暂停当前函数执行,等待右侧表达式 resolve 后继续”,而这种暂停机制依赖函数体被运行时识别为异步上下文(即由 async 标记)。
- 错误写法:
function bad() { const data = await fetch('/api').then(r => r.json()); // ❌ 报错:SyntaxError: await is only valid in async function } - 正确写法:
async function good() { const response = await fetch('/api'); const data = await response.json(); // ✅ 在 async 函数内,await 才合法 return data; }
await 等待的到底是什么?非 Promise 值会怎样?
await 后面可以跟任意值,不只是 Promise:
立即学习“Java免费学习笔记(深入)”;
- 如果是
Promise,它会等待该 Promise 进入fulfilled状态,并把resolve的值赋给左边变量; - 如果不是
Promise(比如数字、字符串、对象),await会立即返回该值,不阻塞也不异步化——它只是“假装等一下”,然后继续执行。
这说明:await 100 和 await Promise.resolve(100) 行为一致,但前者毫无异步意义,纯属冗余。
async function demo() {
console.log(await 100); // 立即输出 100
console.log(await Promise.resolve(200)); // 立即输出 200(微任务队列中 resolve)
console.log(await Promise.reject('oops')); // ❌ 抛出未捕获异常,除非 try/catch
}如何避免 await 顺序等待拖慢性能?
连续 await 是串行的,比如先请求用户、再根据用户 ID 请求订单,这是合理串行;但如果两个请求彼此无关(如获取用户 + 获取公告),用串行就浪费了网络并行能力。
- ❌ 低效串行:
const user = await fetch('/user'); const notice = await fetch('/notice'); // 要等 user 完成才发请求 - ✅ 并行优化:
const [user, notice] = await Promise.all([ fetch('/user'), fetch('/notice') ]);
Promise.all 适合“全部成功才继续”的场景;若某一项失败不能导致整体失败,改用 Promise.allSettled。
注意:await 本身不提供并发控制,它只是语法;并发逻辑仍需靠 Promise.all、Promise.race 等原语组织。
错误处理为什么必须用 try/catch?Promise.catch 不行吗?
可以,但不推荐混用。因为 await 把异步错误“同步化”了——reject 会直接以异常形式抛出,就像 throw 一样,所以自然该用 try/catch 捕获。
- ✅ 推荐(清晰、集中、符合直觉):
async function load() { try { const res = await fetch('/data'); if (!res.ok) throw new Error(`HTTP ${res.status}`); return await res.json(); } catch (err) { console.error('加载失败:', err); throw err; // 或返回默认值 } } - ⚠️ 混用(易漏、难维护):
fetch('/data') .then(r => r.json()) .catch(err => console.error(err)); // 无法捕获 fetch 自身 network error(需在外层加 catch)
关键点:未被 try/catch 包裹的 await 错误,会变成 rejected Promise,如果调用方没链上 .catch() 或再次 await,就会触发全局 unhandledrejection —— 这类错误在生产环境极难定位。
真正的坑不在语法,而在习惯:把 await 当同步写,却忘了它背后仍是事件循环和微任务调度;一旦漏掉 try/catch、滥用串行、或误以为 await 能“取消”正在运行的 Promise,问题就会悄无声息地堆积。











