catch 本质是 then(null, onrejected) 的语法糖,处理上游 rejection 后默认返回 fulfilled 状态 promise;若需中断链,须在 catch 中 throw 错误、返回 promise.reject() 或将其置于链末端。

因为 catch 回调执行成功后,默认返回一个 fulfilled 状态的新 Promise,后续的 then 自然会接收到这个“已解决”的值并执行。
catch 本质是 then(null, onRejected)
catch(fn) 是 then(null, fn) 的语法糖。它只处理上游的 rejection,但自身仍会返回一个新的 Promise —— 这个新 Promise 的状态,由 fn 的执行结果决定:
- 如果
fn正常结束(哪怕只是console.log()),返回值(包括undefined)会被Promise.resolve()包装,新 Promise 状态为 fulfilled - 如果
fn内部throw错误,或显式返回Promise.reject(...),新 Promise 状态才是 rejected
错误被“消化”后,链就继续走 fulfilled 路径
例如:
Promise.reject('oops')
.catch(err => console.log(err)) // 打印 'oops',返回 Promise.resolve(undefined)
.then(val => console.log('then runs:', val)); // 输出 'then runs: undefined'
这里 .catch() 吃掉了错误,没抛新错,也没返回 rejected Promise,所以链没有中断,而是带着 undefined 进入下一个 then。
想让链真正终止?得主动制造 rejection
若希望错误处理后不再执行后续 then,有几种可靠方式:
- 在
catch中重新抛出错误:catch(err => { handleError(err); throw err; }) - 在
catch中返回一个明确拒绝的 Promise:catch(err => { handleError(err); return Promise.reject(err); }) - 把
catch放到链最末端,不接任何后续then—— 这是最常见也最安全的做法
微任务队列不影响这个逻辑,只影响执行时机
有人误以为“catch 没立刻执行,所以 then 先跑了”,其实不是。所有 then/catch 回调都按微任务顺序排队,但状态流转规则始终如一:上一个环节返回 fulfilled Promise,下一个 then 就必然触发;返回 rejected,才轮到下一个 catch 或链末的全局捕获。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











