2020-08-29 17:00:02
在 JavaScript 中优雅地处理异步操作错误,需结合现代语法与分层策略,构建覆盖局部捕获、逻辑复用、链式兜底、全局监控的完整机制。以下是具体实现方案:
1. 使用 async/await + try/catch 同步式捕获async 函数返回 Promise,内部错误会被自动拒绝,通过 try/catch 可同步捕获:
async function fetchData() { try { const res = await fetch('/api/data'); if (!res.ok) throw new Error(res.statusText); return await res.json(); } catch (err) { console.error('请求失败:', err.message); // 可选择重新抛出、返回默认值或执行补偿逻辑 throw err; // 或 return { default: true }; }}当多个异步函数需统一错误处理时,封装高阶函数复用逻辑:
function withErrorHandling(asyncFn) { return async (...args) => { try { return await asyncFn(...args); } catch (err) { console.error(`执行 ${asyncFn.name} 失败:`, err); // 可扩展:错误上报、用户提示、返回默认值 return null; // 或 throw new CustomError(); } };}// 使用示例const safeFetchData = withErrorHandling(fetchData);const data = await safeFetchData(); // 错误已内部处理即使使用 .then() 链式调用,也需确保每个链有 .catch():
fetch('/api/data') .then(res => { if (!res.ok) throw new Error(res.statusText); return res.json(); }) .then(data => console.log(data)) .catch(err => console.error('链式捕获:', err)); // 兜底所有异常通过 unhandledrejection 事件捕获漏掉的异常,避免静默失败:
window.addEventListener('unhandledrejection', event => { console.warn('未处理的 Promise 错误:', event.reason); // 可选:上报错误或提示用户 event.preventDefault(); // 阻止浏览器默认警告});// Node.js 环境process.on('unhandledRejection', (reason, promise) => { console.error('未处理的拒绝:', reason);});将上述方法结合,形成分层处理:
// 1. 封装带错误处理的异步函数async function fetchWithRetry(url, retries = 3) { return withErrorHandling(async () => { for (let i = 0; i < retries; i++) { try { const res = await fetch(url); if (!res.ok) throw new Error(res.statusText); return await res.json(); } catch (err) { if (i === retries - 1) throw err; // 最后一次重试失败则抛出 await new Promise(resolve => setTimeout(resolve, 1000)); // 等待后重试 } } })();}// 2. 调用时局部捕获async function main() { try { const data = await fetchWithRetry('/api/data'); console.log(data); } catch (err) { console.error('最终失败:', err); }}// 3. 全局兜底window.addEventListener('unhandledrejection', event => { console.error('全局捕获:', event.reason);});main();总结业务逻辑层:async/await + try/catch。
复用逻辑层:高阶函数封装。
链式调用层:.catch() 兜底。
全局监控层:unhandledrejection 事件。
通过以上方法,可实现既优雅又健壮的异步错误处理机制。