通用错误处理的核心是结构化“捕获→分类→响应→透传/终止”流程,通过高阶函数封装异步操作、定义分层错误类型、设置全局兜底并避免常见陷阱。

设计通用的错误处理逻辑,核心不是写一堆重复的 try/catch,而是把“捕获 → 分类 → 响应 → 透传/终止”这一流程结构化、可复用。重点在于统一入口、区分错误类型、保留上下文,并留出扩展空间。
封装带错误处理的 async 函数包装器
用高阶函数包裹异步操作,自动注入错误处理逻辑,避免每个调用处都写 try/catch:
- 返回一个
[error, result]元组(类似 Go 或 Node.js 传统风格),让调用方显式判断 - 支持传入自定义错误处理器(如日志上报、用户提示、重试策略)
- 保留原始 Promise 的链式能力,不破坏 await 流程
示例:
function withError(fn, handler = console.error) {
return async function(...args) {
try {
const result = await fn(...args);
return [null, result];
} catch (err) {
handler(err, { fnName: fn.name || 'anonymous', args });
return [err, null];
}
};
}
// 使用
const safeFetch = withError(fetch);
const [err, res] = await safeFetch('/api/user');
if (err) {
// 统一处理网络失败
} else {
// 正常解析
}
定义分层错误类型并分类响应
不要只用 Error 实例,而是创建语义化子类,让错误可识别、可路由:
-
NetworkError:请求超时、断网、5xx 状态码 → 触发重试或降级 UI -
ValidationError:400 或表单校验失败 → 展示具体字段提示 -
AuthError:401/403 → 跳转登录或清空凭证 -
BusinessError:业务规则拒绝(如库存不足)→ 显示友好文案,不暴露技术细节
在 catch 中用 instanceof 或 err.type 分支处理,而不是统一弹窗“出错了”。
统一兜底 + 上下文增强
再完善的局部处理,也难免遗漏。必须设置全局防线,并为错误附加运行时上下文:
- 监听
unhandledrejection,记录未被捕获的 Promise 拒绝(注意:event.reason可能是 Error 或普通值) - 在错误对象中手动添加关键信息:当前页面路径、用户 ID、请求 URL、时间戳、堆栈截断片段
- 对生产环境错误,避免直接
console.error,改用日志 SDK 上报,并设置采样率防刷
示例:
window.addEventListener('unhandledrejection', event => {
const err = event.reason instanceof Error
? event.reason
: new Error(String(event.reason));
err.context = {
url: location.href,
timestamp: Date.now(),
userId: window.__USER_ID__
};
logError(err); // 自定义上报函数
});
避免常见陷阱
通用逻辑容易因疏忽失效:
- 不 await 内部异步调用:即使外层有
try/catch,漏掉await就等于放弃控制权 - Promise 链末尾缺失
.catch():用then().then().catch()替代then().catch().then(),否则中间 reject 会跳过后续 then - 吞掉错误却不处理:空
catch或只console.log而不做任何响应,等于静默失败 - 错误类型判断不严谨:用
err.constructor.name === 'TypeError'不如err instanceof TypeError可靠
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











