前端进阶之旅前端进阶之旅
  • 基础篇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 链抛出异常
JSJavaScript异步与 Promise

在 then 回调中抛出异常,Promise 链会如何反应?

在 then 回调中抛出同步异常,该异常会被自动捕获,导致返回的新 Promise 变为 rejected,异常值成为拒绝原因,链上后续 then 的成功回调不会执行,交给后续 catch 处理。

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

then 返回的 Promise 也会被拒绝

  1. 异常捕获then 回调内的 throw 等价于 reject
  2. 链式传播拒绝沿链向下找 catch 处理
  3. 返回值包裹任何返回值都会被 Promise.resolve 包裹

仅捕获 then 回调中同步抛出的异常;setTimeout 等异步回调中的直接 throw 无法捕获。

核心回答

先记住这个答案

then 回调抛出的异常会被 Promise 机制捕获,使 then 返回的新 Promise 进入 rejected 状态。因此,异常会沿着链向下传播,直到遇到 catch 或拒绝处理回调。若链末端没有捕获,会产生未处理的拒绝。捕获范围仅限该回调及其内部同步操作,异步操作中抛出的异常不会自动捕获。

  • 回调抛异常自动转为拒绝
  • 后续 then 的成功回调不执行
  • 未捕获则触发 unhandledrejection

then 返回新 Promise 的决议机制

调用 promise.then(onFulfilled, onRejected) 时,会立即返回一个全新的 Promise(记为 p2)。当原始 Promise 变为 fulfilled 后,JavaScript 会将 onFulfilled 放入微任务队列。执行该回调时,如果它抛出异常,这个异常会被隐式捕获,并作为 p2 的拒绝原因,使 p2 直接进入 rejected 状态。这一机制与 Promise 构造器中 executor 抛错相似,但发生在 then 中。

若 onFulfilled 正常返回一个值(包括 undefined),p2 会以该值被 resolve;若返回一个 thenable 或 Promise,p2 会等待它 settle 后再决议。抛出异常相当于返回一个 rejected Promise,因此链上的下一个 then 若没有提供 onRejected,就会跳过其成功回调,直到遇到 catch 或同级的失败处理。这种设计保证错误不会丢失,会沿链传递。

then 抛异常使链转为 rejectedJavaScript
Promise.resolve(1)
  .then(v => {
    console.log('first then, value:', v);
    throw new Error('boom');
  })
  .then(() => console.log('second then fulfilled'))
  .catch(err => console.log('caught:', err.message));
// 输出:
// first then, value: 1
// caught: boom
查看输出与解释
first then, value: 1
caught: boom

第二个 then 不会执行,因为第一个 then 抛出的异常使链变为 rejected,直接跳到 catch。

读取用户配置时的错误中断流程

假设从服务端获取用户配置后,需要解析 JSON 并校验必填字段。代码写成 fetchConfig().then(JSON.parse).then(validate).then(render)。若 fetchConfig 成功但服务器返回畸形 JSON,JSON.parse 会抛同步错误,该错误自动使第二个 then 返回的 Promise 变为 rejected,从而跳过 validate 和 render,直接进入链尾的 catch。这样避免了无效数据继续流向界面。

若在 validate 中又发现字段缺失而主动抛出 ValidationError,同样会继续沿链走到同一 catch。因此,链式 then 中任何一步的同步异常都会中断后续所有成功回调。若需要针对不同错误做不同处理,可链上插入多个 catch 以细分,但注意只有 catch(或 then 的 onRejected 回调)可以恢复链。

异常捕获仅作用于同步部分

如果回调内部启动了异步操作(如 setTimeout),在异步回调中抛出的异常不会被 Promise 捕获。例如 Promise.resolve().then(() => setTimeout(() => { throw new Error('later'); })),这个异常直接成为全局未捕获异常,不会影响该 then 返回的 Promise,因为此时同步回调已结束,Promise 已决议。因此,要在异步任务中传播错误,应返回一个 Promise,并让该 Promise 在异步失败时被拒绝,而不是在异步回调中直接 throw。

另外,若 then 回调中调用 reject 风格的函数是不存在的,因为 Promise 是构造器中的参数。正确的处理是返回一个 rejected Promise,如 return Promise.reject(new Error()),效果等同抛异常。但两种方式在链上处理相同。还需注意不应混淆 try/catch 的作用,Promise 的内部捕获机制已自动处理同步异常,无需手工包裹。

回答前,多想一步

容易答错的地方

认为异常会冒泡到外层 try/catch
有人以为 then 回调中抛错能被外部 try/catch 捕获。实际上,then 回调在微任务中执行,已脱离同步调用栈,外层 try/catch 无法捕获,必须使用 Promise 的拒绝处理机制。
混用异步抛错与同步 throw
认为在 then 回调里写 setTimeout 内 throw 也会被 Promise 捕获。错,Promise 只捕获回调同步执行的异常,异步回调中的异常不会影响链的状态,只会成为全局错误。
试着用自己的话回答

面试官还会怎么问?

如何在 then 回调中主动产生一个拒绝而不使用 throw?

可以返回一个 rejected Promise,如 return Promise.reject(new Error())。这样效果与 throw 相同,但更显式,便于表达意图,且利于链式流程控制。

如果 then 回调抛出的异常是一个字符串而非 Error 对象,链后续能正确处理吗?

可以。Promise 会将该值作为拒绝原因,不影响状态转变。但抛出字符串会使错误堆栈缺失,建议始终抛 Error 对象以便调试。

then 回调中抛出异常与调用 onRejected 后抛出异常有何不同?

无论哪个回调抛出异常,都会使 then 返回的新 Promise 变为 rejected。因此,如果 onRejected 本身抛错,会继续沿链寻找下一个 catch,这可能导致原始错误被覆盖。

从一道题,走向一组知识

把知识连起来

异步与 Promise

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

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

异步与 Promise

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

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

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

参考资料

  • Using promises

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

本题目录
  1. 先记住这个答案
  2. then 返回新 Promise 的决议机制
  3. 读取用户配置时的错误中断流程
  4. 异常捕获仅作用于同步部分
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

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

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