前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库Promise executor 抛出错误会拒绝吗
JavaScript异步与 Promise

在 new Promise 的 executor 里直接 throw,Promise 会变成 rejected 吗?

会。executor 同步执行时抛出的错误,会被 Promise 构造器自动捕获,效果等同于调用 reject(err),错误不会冒泡到 new Promise 外面。但只限于同步抛出的错误,在 executor 里的 setTimeout 回调中抛错,构造器就接不住了。

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

构造器只接得住同步错误

  1. 同步 throw构造器用内部的 try...catch 包着 executor,捕获后调用 reject
  2. 状态锁定已经 resolve 过,再抛错也不会改状态,错误被吞掉
  3. 异步 throwsetTimeout 回调执行时 executor 早已返回,错误变成全局未捕获异常

构造器把错误转成了拒绝,不代表错误被处理了。如果这个 Promise 没有接 catch,浏览器依然会在控制台报 Uncaught (in promise) 错误。

核心回答

先记住这个答案

会。Promise 构造器在调用 executor 时,内部相当于包了一层 try...catch,executor 里同步抛出的错误会被捕获,然后当作拒绝原因调用 reject。所以 new Promise(() => { throw new Error('x') }) 得到的是一个 rejected 的 Promise,后面接 catch 能拿到这个 Error 对象。有两个例外要记住:如果 throw 之前已经 resolve 过,错误会被忽略;如果错误是在 executor 里的异步回调中抛出的,构造器捕获不到。

  • executor 同步 throw 等同于 reject(err)
  • resolve 之后再 throw,错误被静默忽略
  • 异步回调里的 throw 构造器接不住,Promise 一直 pending
  • 外层 try...catch 包 new Promise 抓不到这个错误

同步抛错和 reject 效果一样

先看最基本的情况。executor 里直接 throw,外面的代码不会中断,错误进了 catch。

executor 里 throw 之后用 catch 接住JavaScript
const p = new Promise(() => {
  throw new Error('配置缺失') // 同步抛错
})

console.log('构造完成,代码没有中断')

p.catch((err) => {
  console.log('捕获到:', err.message)
  console.log('是 Error 实例:', err instanceof Error)
})
查看输出与解释
构造完成,代码没有中断
捕获到: 配置缺失
是 Error 实例: true

第一行打印说明错误没有从 new Promise 抛出去,同步代码照常往下执行。错误变成了 Promise 的拒绝原因,等微任务阶段交给 catch 回调。 这个行为很实用。比如 executor 里要先 JSON.parse 一段配置再发请求,JSON.parse 抛出的 SyntaxError 不用自己 try...catch,它会自动变成拒绝,调用方统一在 catch 里处理就行。

throw 和 reject 的一个区别
reject(err) 只是改状态,后面的代码会继续执行;throw 会立刻中断 executor,后面的语句不再运行。所以在 executor 里校验参数时,写 throw 或 return reject(err) 都可以,只写 reject(err) 不加 return 的话,后面的逻辑还会跑一遍。

两个接不住的边界

构造器能捕获,是因为 executor 执行时它就在旁边。离开这个前提,错误就管不了了。

resolve 之后再 throwJavaScript
const p = new Promise((resolve) => {
  resolve('已成功')
  throw new Error('晚了一步') // 状态已锁定,这个错误被忽略
})

p.then(
  (v) => console.log('fulfilled:', v),
  (err) => console.log('rejected:', err.message)
)
查看输出与解释
fulfilled: 已成功

构造器确实捕获到了这个错误,也调用了 reject,但 Promise 状态只能改一次,已经是 fulfilled 的 Promise 不会再变。错误既不会进 catch,也不会在控制台报出来,是真正被吞掉了。线上排查时这种情况最难发现。

异步回调里 throw
如果写成 new Promise(() => { setTimeout(() => { throw new Error('x') }, 0) }),定时器回调执行时 executor 早就返回了,构造器的那层 try...catch 已经不在调用栈上。这个错误会变成一个普通的全局未捕获异常,而 Promise 因为从没调用过 resolve 或 reject,会一直停在 pending,挂在它上面的 then 和 catch 永远不会执行。正确写法是在异步回调里显式调用 reject(err),或者在回调内部自己 try...catch 再 reject。
回答前,多想一步

容易答错的地方

以为外层 try...catch 能抓住
try { new Promise(() => { throw err }) } catch (e) {} 里的 catch 永远不会执行,因为错误已经被构造器转成拒绝了,没有从 new 表达式里抛出来。要处理只能用 .catch(),或者在 async 函数里 await 这个 Promise 再 try...catch。
以为错误被捕获就等于被处理
构造器只是把「抛出」换成了「拒绝」。如果没有任何 catch 处理这个 Promise,浏览器会在控制台打印 Uncaught (in promise),Node.js 会触发 unhandledRejection 事件,较新版本默认直接让进程退出。
以为 throw 一个字符串也能拿到 err.message
构造器会原样把抛出的值作为拒绝原因。throw '出错了' 时 catch 拿到的就是字符串,err.message 是 undefined,也没有调用栈。所以要 throw new Error(...)。
试着用自己的话回答

面试官还会怎么问?

then 回调里 throw 会怎样?

和 executor 里一样,then 返回的新 Promise 会以这个错误拒绝,错误沿着链往后传,直到遇到第一个 catch 或带第二个参数的 then。

async 函数里同步 throw 呢?

也一样。async 函数体内任何位置抛出的错误都会被转成返回的 Promise 的拒绝,调用 async 函数本身不会抛错。所以调用时忘了 await 或 catch,错误就会变成未处理拒绝。

怎么把一个回调风格的异步 API 安全地包成 Promise?

在 executor 里调用这个 API,回调里根据是否有错误分别调用 reject(err) 和 resolve(data),不要在回调里 throw。Node.js 里可以直接用 util.promisify 帮你做这件事。

从一道题,走向一组知识

把知识连起来

异步与 Promise

then 回调里返回一个 Promise,下一个 then 拿到的是 Promise 还是值?

then 回调里 throw 也会让返回的 Promise 拒绝,和 executor 里 throw 是同一种错误转换。

异步与 Promise

Promise.race 传一个空数组进去,会返回什么?

异步回调里抛错会让 Promise 永远 pending,Promise.race([]) 是另一种永远不结束的情况。

参考资料

  • JavaScript:异步与 Promise参考资料

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

本题目录
  1. 先记住这个答案
  2. 同步抛错和 reject 效果一样
  3. 两个接不住的边界
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

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

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