捕获未处理的 promise rejection 需要同时注册全局事件监听器,分别处理 unhandledrejection 和 rejectionhandled。前者在拒绝发生且未被 catch 时触发,后者在拒绝被后续代码处理后触发,通过对比两次事件的 promise 对象可以过滤掉已处理的错误。这种组合方式能确保所有潜在的异步错误都被记录或拦截。

如何区分未处理和已处理的拒绝
区分的关键在于利用 unhandledrejection 事件中的 event.promise 属性。当 Promise 被拒绝时,如果没有任何 .catch() 或 try...catch 块与之关联,浏览器会派发该事件。随后,如果开发者补上了错误处理逻辑,引擎会派发 rejectionhandled 事件。因此,核心策略是维护一个待处理拒绝的集合,在收到 unhandledrejection 时将其加入集合,并在收到 rejectionhandled 时将其移除。最终留在集合中的即为真正未处理的错误。

const pendingRejections = new Set();
window.addEventListener('unhandledrejection', (event) => {
pendingRejections.add(event.promise);
console.error('Unhandled Rejection:', event.reason);
});
window.addEventListener('rejectionhandled', (event) => {
pendingRejections.delete(event.promise);
});
// 模拟一个未处理的拒绝
Promise.reject(new Error('Test Error'));
运行上述代码后,控制台会输出一条错误信息。由于没有为这个 Promise 添加 .catch(),它始终处于未处理状态,因此 pendingRejections 集合中会保留该 Promise 对象。如果改为 Promise.reject(new Error('Test Error')).catch(() => {}),则不会触发 unhandledrejection,或者会立即触发 rejectionhandled 从而从集合中移除,具体取决于执行时序,但通常不会被记录为未处理。
如何处理不同环境下的全局捕获
在不同 JavaScript 运行环境中,全局错误捕获的机制略有差异。在浏览器中,除了事件监听器,还可以使用 window.onerror 或 window.addEventListener('error'),但这些主要针对同步错误或资源加载失败,对 Promise 无效。在 Node.js 环境中,推荐使用 process.on('unhandledRejection')。为了兼容多种环境,可以封装一个统一的工具函数,根据 typeof window 来判断当前环境并注册相应的监听器。这样可以确保无论是在前端页面还是后端服务中,都能有效地监控异步错误。
Java开发手册规约集合,基于阿里巴巴Java开发手册(嵩山版)。 涵盖7大维度:编程规约、异常日志、单元测试、安全规约、MySQL数据库、工程结构、设计规约。

function setupGlobalErrorHandling() {
if (typeof window !== 'undefined') {
// Browser environment
window.addEventListener('unhandledrejection', (event) => {
console.error('Browser Unhandled Rejection:', event.reason);
event.preventDefault(); // Prevent default browser logging
});
} else {
// Node.js environment
process.on('unhandledRejection', (reason, promise) => {
console.error('Node.js Unhandled Rejection:', reason);
});
}
}
setupGlobalErrorHandling();
// Test in both environments
Promise.reject(new Error('Global Test'));
在 Node.js 中,如果不处理未解决的 Promise,进程可能会在退出时发出警告甚至崩溃(取决于版本和配置)。而在浏览器中,未处理的拒绝通常只会导致控制台报错,不会影响页面其他脚本的执行。通过上述封装代码,可以在两种环境下都获得一致的日志输出,便于统一监控和分析。
未处理拒绝在长时间运行的应用中有何影响
在长时间运行的应用中,未处理的 Promise rejection 会导致内存泄漏。因为每个未处理的 Promise 对象都会保留在 pendingRejections 集合中,如果这些 Promise 对应的错误从未被处理,它们将一直占用内存。此外,大量的未处理错误会淹没控制台日志,使得真正的关键错误难以被发现。因此,定期清理或限制 pendingRejections 集合的大小是必要的优化措施。例如,可以设置一个最大容量,当超过容量时丢弃最旧的条目,或者在应用关闭时强制处理所有剩余的错误。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










