JavaScript异步错误拦截装饰器通过try/catch包装函数,支持同步/异步混合、fallback、静默失败等策略,但无法捕获未await的Promise拒绝、宏任务错误及语法错误。

在 JavaScript 中,可以编写一个通用的异步错误统一拦截装饰器函数,核心思路是:接收一个异步函数,返回一个新函数,在调用时自动 try/catch 并将错误交由统一处理逻辑(如上报、提示、重试等),同时保持原函数的参数、返回值和 `this` 上下文不变。
基础版:简单包装 Promise
适用于普通 async 函数或返回 Promise 的函数:
function withErrorBoundary(handler, onError = console.error) {
return async function(...args) {
try {
return await handler.apply(this, args);
} catch (err) {
onError(err, { func: handler.name || 'anonymous', args });
throw err; // 可选:继续抛出,让调用方仍可自行处理
}
};
}
使用示例:
const fetchData = withErrorBoundary(async (url) => {
const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
}, (err) => {
alert('请求失败,请稍后重试');
// 上报错误到监控系统...
});
// 调用时行为不变,但错误已被拦截
fetchData('/api/user').catch(() => {}); // 错误已处理,这里不会进入 catch(除非显式 re-throw)
增强版:支持同步/异步混合 & 自定义恢复策略
更健壮的版本能兼容同步函数(自动 Promise 化)、提供默认 fallback 值、支持静默失败(不抛错):
function createErrorHandler({
onError = console.error,
fallback = undefined,
shouldRethrow = true,
silent = false
} = {}) {
return function(handler) {
return function(...args) {
let result;
try {
result = handler.apply(this, args);
} catch (err) {
onError(err, { func: handler.name, args });
if (silent) return fallback;
if (shouldRethrow) throw err;
return fallback;
}
// 处理 Promise 返回值
if (result instanceof Promise) {
return result.catch(err => {
onError(err, { func: handler.name, args });
if (silent) return fallback;
if (shouldRethrow) throw err;
return fallback;
});
}
return result;
};
};
}
用法:
- 包裹 async 函数:
const safeFetch = createErrorHandler({ onError: reportError })(async () => {...}) - 包裹普通函数:
const safeParse = createErrorHandler({ fallback: null })(JSON.parse) - 静默容错:
createErrorHandler({ silent: true, fallback: [] })→ 出错时直接返回空数组
实际工程建议
真实项目中建议结合具体场景微调:
- 区分错误类型:对网络超时、4xx、5xx 或业务码做不同响应(例如 401 触发登出,429 自动退避重试)
- 避免重复上报:在
onError中加防抖或去重逻辑(如按 error.message + stack hash) - 保留原始调用栈:用
err.stack和new Error().stack补充上下文 - 与 React/Vue 等框架集成时,可将
onError关联到全局错误边界或响应式状态
注意事项
这类装饰器无法捕获以下错误:
- 未被 await 的 Promise 拒绝(即“unhandledrejection”)→ 需额外监听
window.addEventListener('unhandledrejection') - 宏任务/定时器中的异步错误(如
setTimeout(() => { throw e; }))→ 不在装饰器作用域内 - 语法错误、顶层 await 失败等解析/初始化阶段错误 → 运行前就已崩溃


















