async/await 中需用 try/catch 包裹 await 表达式而非整个函数,因 async 返回 Promise,错误仅在 await 遇到 reject 时转为可捕获异常;未 await 的 Promise 错误会变成 unhandledrejection。

在 async/await 中,不能直接用 try/catch 包裹整个异步函数定义,而要包裹 await 表达式本身。因为 async 函数返回的是 Promise,错误不会同步抛出,只有 await 等待 Promise 拒绝(reject)时,才会把 rejection 转为可捕获的异常。
正确写法:try/catch 包住 await 调用
只要 await 后面的 Promise 被 reject,就会被 catch 捕获,就像同步错误一样处理:
<!-- 示例 -->
async function fetchData() {
try {
const res = await fetch('https://api.example.com/data');
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
return data;
} catch (err) {
console.error('请求失败:', err.message);
// 可以返回默认值、重试,或重新 throw
throw err; // 或 return null;
}
}多个 await 需要统一兜底还是分别处理?
常见场景是串行调用多个异步操作。如果任一环节出错都应中断流程,就用一个 try/catch 包住全部 await;如果想让某个步骤失败不影响后续,就单独 try/catch 该 await:
立即学习“Java免费学习笔记(深入)”;
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 统一兜底(推荐多数情况):适合“全成功才继续”的逻辑,如登录 → 获取用户信息 → 加载配置
- 局部捕获:适合“尽力而为”,比如上报日志失败不阻塞主流程,可单独包一层 try/catch
注意:Promise.all 和 Promise.allSettled 的错误行为
它们本身不抛错,但 await 它们的结果时表现不同:
- await Promise.all([...]):任一 Promise reject,整个 all 立即 reject,会被外层 catch 捕获
- await Promise.allSettled([...]):永远 resolve,返回每个 Promise 的 { status, value | reason },需手动检查 status 是否为 'rejected'
所以用 Promise.all 时,错误自然进 catch;用 allSettled 则通常不需要 try/catch,而是做状态判断。
不要忽略未 await 的 Promise
以下写法无法捕获错误:
async function badExample() {
try {
fetch('/api'); // ❌ 没 await!这个 Promise 被创建后就不管了,错误会变成 unhandledrejection
} catch (e) {
// 这里永远进不来
}
}必须 await 才能触发错误转译。如果确实不想等(比如发个后台日志),至少要用 .catch() 处理拒绝:
fetch('/log').catch(console.error); // 避免 unhandledrejection

















