前端进阶之旅前端进阶之旅
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
首页程序员面试题库Promise catch 位置差异
JSJavaScript异步与 Promise

catch 放在 Promise 链的不同位置(末尾与中间)会产生哪些不同的错误处理结果?

在 Promise 链中,catch 只会捕获它之前(不含自身)出现的拒绝,放在中间与末尾会导致后续 then 是否能执行以及错误是否被默默吞掉的结果截然不同。

前端进阶之旅 · 一题精讲更新于 2026.09.05
JavaScript#异步与 Promise#异步编程
先看核心答案
理解线索

catch 是链式中的过滤器

  1. 捕获区间从链头到 catch 前
  2. 返回新Promise决定链的走向
  3. 恢复能力onRejected 正常返回即恢复

链上每个 then/catch 都会产生新 Promise,错误只沿链向下寻找最近的处理函数。

核心回答

先记住这个答案

catch 本质是 then(undefined, onRejected),它返回一个新的 Promise。放末尾时,它能捕获整条链上所有先于它产生的拒绝,并终止链;放中间时,它只捕获从链起点到该 catch 之前产生的拒绝,之后如果继续 then,链会被恢复,错误不再向外传递,但若后面的 then 又抛出异常,则需要再追加 catch 才能处理。

  • catch 只捕获其之前的拒绝
  • 中间 catch 后链恢复执行
  • 末尾 catch 兜住整链错误

catch 的链式传播规则

Promise.prototype.catch(onRejected) 等价于 then(undefined, onRejected),它返回一个新 Promise 并立即将其挂到原 Promise 上。如果原 Promise 已经变为 rejected,onRejected 会以该拒绝原因作为参数异步执行;若原 Promise 是 fulfilled,则跳过 onRejected,新 Promise 直接以原值兑现。

由此可知,catch 只关心其调用位置之前的拒绝,并且它的 onRejected 的返回值会成为新 Promise 的兑现值,从而把错误“吞掉”并让链后续走到 then 的成功回调。如果 onRejected 内部抛出异常或返回 rejected Promise,则新 Promise 再次被拒绝,需由后面的 catch 接住。

两个异步请求的失败场景

假设一个函数先请求用户资料,再请求用户订单,两个都是返回 Promise 的异步请求。当 catch 放在中间(后面还有 then)时,例如 fetchUser().then(fetchOrders).catch(err => { log(err); return defaultOrders; }).then(render),若 fetchUser 成功但 fetchOrders 失败,catch 捕获该失败并返回默认订单,后续 then(render) 会收到默认值并正常渲染;若 fetchUser 本身失败,同样被捕获。这样错误被就地处理,整条链继续运行。

若把 catch 放在末尾,即 fetchUser().then(fetchOrders).then(render).catch(err ⇒ { notify(err); }),则两个步骤中任一失败都会走到这个 catch,但 catch 之后没有任何 then 来恢复页面,只会通知用户,页面停留原状。要恢复,需要在 catch 中返回兜底数据或在前一个 then 中加内部 catch。

位置不是万能的边界条件

中间 catch 并非全能:它只能捕获当其被加入链时已经产生和后续依次传播的错误。若在 catch 之后的 then 回调里发生了异步错误(如 setTimeout 内 throw),该错误不会进入 Promise 链,catch 无法感知,会触发 unhandledrejection 或直接抛到全局。

为覆盖这种情况,应尽量把同步错误和 Promise 拒绝集中在链上,对真正的异步事件使用 async/await 配合 try/catch,或在回调内显式调用 reject。如果坚持使用链式,则需要在每个异步入口处将抛错转为 Promise 拒绝,例如包一个 new Promise 并把异常传给 reject,代价是增加样板代码。

回答前,多想一步

容易答错的地方

认为 catch 放末尾能捕获所有错误
事实是,若 catch 是真正的链尾(后面没有任何 then),它确实能捕获其之前所有拒绝。但如果 catch 之后又接上了 then(即它不再是末尾),那么该 then 回调中抛出的新异常(同步 throw 或返回 rejected Promise)无法被这个 catch 捕获,需要再追加一个 catch 才能处理。
误以为 catch 会终结 Promise 链
catch 返回一个 fulfilled Promise(除非 onRejected 抛错),所以链可以继续 then。很多人学到 catch 就认为错误被吞后停止,实际上它会恢复成正常值,这正是中间位置能提供降级逻辑的依据。
试着用自己的话回答

面试官还会怎么问?

catch 的 onRejected 中返回 rejected Promise,后续链会怎样?

返回的 rejected Promise 会让 catch 返回的新 Promise 变为 rejected,错误携带该 reason 继续向下。若后面没有 catch,会触发 unhandledrejection;若有,则被其捕获,类似把错误重新抛回链。

多个 catch 连续出现,错误会被哪个捕获?

错误只会被第一个遇到的 catch 捕获。第一个 catch 的 onRejected 得到机会处理,处理完并正常返回后,错误不会传给第二个 catch;如果第一个 catch 抛错或返回 rejected,才会流转到第二个。

catch 与 finally 的位置关系如何影响错误传播?

finally 不返回值只执行清理,若在本就有错误且无 catch 时,finally 执行后错误仍会继续传播。把 catch 放 finally 前可先处理错误,放 finally 后则先执行清理再捕获,但无论如何错误需至少一个 catch 避免未处理。

从一道题,走向一组知识

把知识连起来

异步与 Promise

Promise 的 finally 回调与 then 的回调在行为上有哪些关键差异?

同属「异步与 Promise」专题,接着看 Promise finally 与 then 区别 在具体场景中的处理方式。

异步与 Promise

Promise 构造器中的 executor 是同步执行还是异步执行?

同属「异步与 Promise」专题,接着看 Promise executor 同步执行 在具体场景中的处理方式。

放回知识体系中复习JavaScript 进阶知识

参考资料

  • Promise.prototype.catch()

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. catch 的链式传播规则
  3. 两个异步请求的失败场景
  4. 位置不是万能的边界条件
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑