题目
Promise链式调用与async/await的异常处理
信息
- 类型:问答
- 难度:⭐⭐
考点
Promise链式调用,async/await异常处理,错误传播机制
快速回答
在Promise链中,错误会跳过后续的then直到被catch捕获。使用async/await时:
- 必须用
try/catch处理同步错误 - 异步错误需在Promise调用处捕获
- 未捕获的Promise拒绝会导致全局错误
问题场景
以下代码在用户点击按钮时执行异步操作,分析错误处理缺陷:
// 模拟API请求
const fetchData = () => new Promise((resolve, reject) => {
setTimeout(() => reject('Network error'), 100);
});
// 有缺陷的执行函数
async function handleClick() {
const data = fetchData(); // 缺少await
try {
console.log(data.result); // 尝试读取undefined属性
} catch (e) {
console.log('Caught:', e);
}
}
// 按钮点击触发
document.getElementById('btn').addEventListener('click', handleClick);错误分析
- 错误1:缺少await -
fetchData()返回Promise但未等待,导致data是Pending状态的Promise对象 - 错误2:错误类型混淆 - try/catch只能捕获同步错误,无法捕获异步Promise拒绝
- 错误3:全局未处理拒绝 - 未处理的Promise拒绝可能导致应用崩溃
正确解决方案
async function handleClick() {
try {
const data = await fetchData(); // 正确等待Promise
console.log(data.result);
} catch (e) {
console.error('Request failed:', e);
// 实际项目应添加用户提示
}
}
// 全局兜底错误处理
window.addEventListener('unhandledrejection', event => {
console.error('Unhandled rejection:', event.reason);
event.preventDefault(); // 阻止默认控制台报错
});核心原理
- Promise错误冒泡:拒绝状态的Promise会跳过后续
then直到遇见catch - async/await本质:async函数返回Promise,await会暂停执行直到Promise状态变更
- 错误捕获差异:
- 同步错误:try/catch可直接捕获
- 异步错误:只能通过Promise.catch或async函数内的try/catch捕获
最佳实践
- 始终在
await的Promise外包裹try/catch - 在Promise链末尾添加
catch作为兜底 - 使用
window.addEventListener('unhandledrejection')全局监控未处理错误 - 对于并行操作,用
Promise.allSettled()替代Promise.all()确保所有请求完成
常见陷阱
| 错误写法 | 问题 | 修复方案 |
|---|---|---|
const res = fetchData(); |
未等待异步结果 | 添加await |
promise.then().catch()内使用async |
嵌套异步导致错误处理复杂化 | 统一使用async/await语法 |
在循环中忽略await |
并行/串行执行混乱 | 明确使用Promise.all()或for...of |
扩展知识
- Top-level await:ES2022支持在模块顶层使用await,但需注意阻塞风险
- 错误边界(React):前端框架通常提供组件级错误捕获机制
- AbortController:配合fetch可实现请求超时和取消