未加 catch 或全局兜底会导致 Promise 拒绝触发 unhandledrejection,浏览器报红、Node.js 15+ 可能崩进程;.then() 中 throw 不被上层 catch 捕获,因它返回新 rejected Promise,需下游 .catch() 接收;应监听 window.addEventListener('unhandledrejection') 兜底,且需 e.preventDefault();async/await 更易捕获错误,但并发需注意 Promise.all 与 allSettled 区别;setTimeout 等非 Promise 异步错误需单独监听 error 事件。

没加 catch 或没配全局兜底,Promise 拒绝就会变成 unhandledrejection,浏览器控制台报红、Node.js 15+ 可能直接崩进程。
为什么 .then() 里 throw 不会被上层 catch 捕获?
因为 .then(onFulfilled) 只处理 resolve 状态;里面同步 throw 出的错误,会自动包装成一个新的 rejected Promise,但这个新 Promise 没有后续处理者——除非你显式接 .catch() 或用 .then(null, onRejected)。
-
.then(() => { throw new Error('boom') })→ 返回一个被拒绝的 Promise,不是抛到外层 try/catch - 它和
Promise.reject(new Error('boom'))效果等价,都需下游catch接住 - 如果链尾没
catch,就触发unhandledrejection
如何在 HTML 页面中监听全局未捕获 Promise 错误?
靠 window.addEventListener('unhandledrejection') 捕获所有漏网之鱼,这是生产环境必须加的兜底。
- 只监听一次即可,建议放在
<script>标签最顶部或入口 JS 最早执行处 -
e.reason是拒绝原因,可能是Error实例、字符串、甚至undefined - 别只
console.warn,至少要e.preventDefault()阻止默认警告(尤其 Node.js 环境)
window.addEventListener('unhandledrejection', e => {
e.preventDefault();
console.error('Unhandled promise rejection:', e.reason);
// 上报监控系统、记录日志、展示用户友好提示
});
.catch() 放错位置会导致错误“消失”或“重复传播”
catch 是链式节点,不是 try/catch 块,它的作用域由它在链中的位置决定。
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
立即学习“前端免费学习笔记(深入)”;
- 放在链尾(如
fetch().then().catch())→ 覆盖整条链的 reject 和 then 内部异常 - 放在中间(如
p.then().catch().then())→ 中间catch吃掉错误后返回值(比如'fallback'),后续then会收到该值;但如果它自己又throw或返回Promise.reject(),错误继续往下传 - 多个
catch并存时,前一个已处理的错误不会进后一个,除非你主动让它继续传播
用 async/await 替代链式 then/catch 更不容易漏错误
结构更接近同步代码,错误天然落在 try/catch 范围内,对开发者更友好。
-
await后面如果是 rejected Promise,直接抛出,catch能捕获 - 注意:
await不会自动 catch 多个并发 Promise 的失败,Promise.all([p1, p2])任一失败就 reject,得靠外层 try/catch 包裹 - 若想并发失败不中断,改用
Promise.allSettled(),再手动过滤status: 'rejected'
async function loadUserData() {
try {
const [user, posts] = await Promise.all([
fetch('/api/user').then(r => r.json()),
fetch('/api/posts').then(r => r.json())
]);
render({ user, posts });
} catch (err) {
showError('加载失败,请重试');
}
}
真正容易被忽略的是:Promise 构造函数外的异步错误(比如 setTimeout(() => { throw new Error() }))根本不在 Promise 错误体系内,unhandledrejection 监听不到,得靠 window.addEventListener('error') 单独捕获。这类错误和 Promise 无关,别混为一谈。


















