未处理的 promise 拒绝会触发 unhandledrejection 事件,需在 window(浏览器)或 process(node.js)监听,标准化错误后异步上报,并注意动态 import、多监听器等边界情况。

在 JavaScript 中,未处理的 Promise 拒绝(unhandled rejection)不会自动抛出错误,但会触发 unhandledrejection 事件。正确监听并上报这类事件,是保障前端异常监控完整性的关键一环。
监听 unhandledrejection 事件
该事件在 Promise 被拒绝且**没有被任何 .catch() 或 await 后续处理**时触发。需在全局作用域(如浏览器 window 或 Node.js 的 process)中监听:
- 浏览器环境:绑定到
window对象 - Node.js 环境:绑定到
process对象(注意:Node.js 15+ 默认会终止进程,需显式监听以避免崩溃)
示例(浏览器):
window.addEventListener('unhandledrejection', event => {
// event.reason 是被拒绝的值(可能是 Error 实例,也可能是任意值)
// event.promise 是触发该事件的 Promise 实例
console.warn('Unhandled rejection:', event.reason, 'at', event.promise);
event.preventDefault(); // 阻止默认行为(如控制台警告),仅在你已自行处理时调用
});
区分真实错误与非 Error 拒绝值
Promise.reject() 可传入任意值(字符串、数字、null),不一定是 Error 实例。日志上报前建议做类型判断和标准化:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 若
event.reason是Error实例,提取message、stack、name - 若为原始值(如字符串),包装成简易错误对象便于统一处理
- 避免直接
JSON.stringify(event.reason),可能因循环引用或不可序列化属性报错
推荐做法:
function normalizeError(reason) {
if (reason instanceof Error) return {
message: reason.message,
stack: reason.stack,
name: reason.name,
type: 'Error'
};
return {
message: String(reason),
type: typeof reason
};
}
结合错误监控系统上报(如 Sentry、自建接口)
监听到事件后,应异步上报,避免阻塞主线程或影响当前执行流:
- 使用
setTimeout(..., 0)或queueMicrotask延迟到下一个事件循环周期 - 对上报逻辑加 try/catch,防止上报失败引发新异常
- 添加上下文字段(如页面 URL、用户 ID、SDK 版本)提升排查效率
示例(带防抖与错误防护):
window.addEventListener('unhandledrejection', event => {
const errorInfo = {
...normalizeError(event.reason),
timestamp: Date.now(),
url: location.href,
userAgent: navigator.userAgent
};
queueMicrotask(() => {
try {
fetch('/api/log-error', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ type: 'unhandledrejection', data: errorInfo })
}).catch(() => {}); // 上报失败不抛错
} catch (e) {
// 上报逻辑内部异常兜底(极少见)
console.error('Failed to report unhandled rejection', e);
}
});
event.preventDefault();
});
注意边界情况与最佳实践
以下情况容易遗漏或误判,需特别留意:
- 动态
import()失败也会触发unhandledrejection,应纳入监控 - 多个
unhandledrejection监听器共存时,event.preventDefault()只影响当前监听器,其他仍会收到事件 - 测试阶段可主动触发验证:
Promise.reject(new Error('test'));(确保无 catch) - 上线前务必移除本地
console.warn,避免污染生产日志
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










