乐闻世界logo
搜索文章和话题

如何处理 Promise 的错误?

2月22日 14:07

Promise 的错误处理是使用 Promise 时必须掌握的重要技能。正确的错误处理可以确保程序的健壮性,避免未捕获的错误导致程序崩溃。

错误处理的基本方法

1. 使用 .catch() 方法

.catch() 是 Promise 错误处理的主要方法,它会捕获链中任何地方抛出的错误:

javascript
Promise.resolve() .then(() => { throw new Error('出错了'); }) .catch(error => { console.error('捕获到错误:', error.message); });

2. 在 .then() 的第二个参数中处理

.then() 方法可以接收两个参数:成功回调和失败回调:

javascript
Promise.resolve() .then( result => console.log('成功:', result), error => console.error('失败:', error.message) );

注意:这种方式的错误处理只捕获前一个 Promise 的错误,不会捕获链中后续的错误。

错误传播机制

错误会沿着 Promise 链向下传播

javascript
Promise.resolve() .then(() => { throw new Error('第一个错误'); }) .then(() => { console.log('这行不会执行'); }) .then(() => { console.log('这行也不会执行'); }) .catch(error => { console.error('最终捕获:', error.message); // 输出: 最终捕获: 第一个错误 });

错误可以被捕获后恢复

javascript
Promise.resolve() .then(() => { throw new Error('出错了'); }) .catch(error => { console.error('捕获错误:', error.message); return '恢复后的值'; // 返回一个值,链可以继续 }) .then(value => { console.log('继续执行:', value); // 输出: 继续执行: 恢复后的值 });

常见错误处理场景

1. 网络请求错误处理

javascript
fetch('/api/data') .then(response => { if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); }) .then(data => { console.log('数据:', data); }) .catch(error => { console.error('请求失败:', error.message); // 可以在这里显示错误提示给用户 showErrorToUser('数据加载失败,请稍后重试'); });

2. 多个 Promise 的错误处理

javascript
Promise.all([promise1, promise2, promise3]) .then(results => { console.log('全部成功:', results); }) .catch(error => { console.error('至少一个失败:', error.message); });

3. 使用 Promise.allSettled 处理部分失败

javascript
Promise.allSettled([promise1, promise2, promise3]) .then(results => { results.forEach((result, index) => { if (result.status === 'fulfilled') { console.log(`Promise ${index} 成功:`, result.value); } else { console.error(`Promise ${index} 失败:`, result.reason); } }); });

错误处理的最佳实践

1. 总是添加错误处理

javascript
// 不推荐:没有错误处理 fetch('/api/data') .then(response => response.json()) .then(data => console.log(data)); // 推荐:添加错误处理 fetch('/api/data') .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error(error));

2. 使用 finally 进行清理

javascript
let isLoading = true; fetch('/api/data') .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error(error)) .finally(() => { isLoading = false; console.log('请求完成,无论成功或失败'); });

3. 错误处理要具体

javascript
// 不推荐:笼统的错误处理 Promise.resolve() .catch(error => { console.error('出错了'); }); // 推荐:具体的错误处理 Promise.resolve() .catch(error => { if (error instanceof NetworkError) { console.error('网络错误:', error.message); } else if (error instanceof ValidationError) { console.error('验证错误:', error.message); } else { console.error('未知错误:', error.message); } });

4. 考虑错误恢复策略

javascript
async function fetchDataWithRetry(url, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { try { const response = await fetch(url); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } catch (error) { console.error(`尝试 ${i + 1} 失败:`, error.message); if (i === maxRetries - 1) { throw error; // 最后一次尝试失败,抛出错误 } // 等待一段时间后重试 await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1))); } } }

async/await 中的错误处理

使用 try/catch

javascript
async function fetchData() { try { const response = await fetch('/api/data'); const data = await response.json(); console.log('数据:', data); } catch (error) { console.error('错误:', error.message); // 错误处理逻辑 } }

捕获特定错误

javascript
async function fetchData() { try { const response = await fetch('/api/data'); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } catch (error) { if (error.name === 'TypeError') { console.error('网络连接问题'); } else if (error.message.includes('HTTP error')) { console.error('服务器错误'); } else { console.error('未知错误:', error); } throw error; // 可以选择重新抛出错误 } }

未捕获的 Promise 错误

全局错误处理

javascript
// 处理未捕获的 Promise 错误 window.addEventListener('unhandledrejection', event => { console.error('未捕获的 Promise 错误:', event.reason); // 可以在这里记录错误或显示错误提示 event.preventDefault(); // 阻止默认的错误输出 }); // Node.js 环境中 process.on('unhandledRejection', (reason, promise) => { console.error('未捕获的 Promise 错误:', reason); });

常见错误处理陷阱

1. 忘记在链中添加 catch

javascript
// 危险:没有错误处理 Promise.reject('出错了') .then(result => console.log(result)); // 错误会冒泡到全局,可能导致程序崩溃 // 安全:添加错误处理 Promise.reject('出错了') .then(result => console.log(result)) .catch(error => console.error(error));

2. 在 catch 中忘记重新抛出错误

javascript
// 可能导致问题:错误被吞掉 Promise.reject('出错了') .catch(error => { console.error('捕获错误:', error); // 忘记重新抛出,后续代码会继续执行 }) .then(() => { console.log('这行会执行,即使前面有错误'); }); // 推荐:根据情况决定是否重新抛出 Promise.reject('出错了') .catch(error => { console.error('捕获错误:', error); // 如果错误无法恢复,重新抛出 throw error; });

3. 混用 then 的第二个参数和 catch

javascript
// 不推荐:容易混淆 Promise.resolve() .then( result => console.log('成功'), error => console.error('失败1') ) .catch(error => console.error('失败2')); // 推荐:统一使用 catch Promise.resolve() .then(result => console.log('成功')) .catch(error => console.error('失败'));

总结

  1. 总是添加错误处理:使用 .catch()try/catch
  2. 理解错误传播:错误会沿着 Promise 链向下传播
  3. 使用 finally 清理:无论成功或失败都要执行的代码放在 finally
  4. 具体化错误处理:根据错误类型进行不同的处理
  5. 考虑错误恢复:实现重试机制或降级策略
  6. 避免错误吞掉:确保错误被正确处理或重新抛出
  7. 全局错误监控:使用全局错误处理器捕获未处理的错误
标签:Promise