throw 是同步中断,立即拒绝 Promise 且保留原始堆栈;return Promise.reject(...) 是返回已拒绝 Promise,executor 正常结束且堆栈指向调用处。

在 Promise 构造函数内部,直接 throw 和 return Promise.reject(...) 看似效果相似,但执行时机、语义意图和错误对象结构有实质差异。
throw 是同步中断,立即触发 Promise 拒绝
在 new Promise((resolve, reject) => { ... }) 的 executor 函数中,只要执行 throw,JS 引擎会立刻终止当前 executor 执行,并把抛出的值作为 rejection reason,隐式调用 reject。这个过程是同步的,且不经过任何额外包装。
- throw 'fail' → Promise 立即 rejected,reason 就是字符串 'fail'
- throw new Error('network') → reason 是 Error 实例,含 stack、message 等完整调试信息
- throw 后面的代码不会执行,哪怕只写了 throw 一行,executor 也戛然而止
return Promise.reject(...) 是显式创建并返回一个已拒绝的 Promise
它不是在当前 executor 中“拒绝”,而是返回一个状态已是 rejected 的 Promise 对象。这个 Promise 本身已经完成初始化,其 [[PromiseState]] 为 "rejected",[[PromiseResult]] 已固定。
- return Promise.reject('fail') → 返回一个被拒绝的 Promise,但 executor 仍会正常结束(无异常中断)
- 它等价于先 new Promise((_, r) => r('fail')),再 return 这个实例
- 适合用于函数式风格:比如工具函数中统一返回 rejected Promise,而非中断流程
错误对象是否保留堆栈信息
这是实际开发中最容易忽略的关键点:
立即学习“Java免费学习笔记(深入)”;
- throw new Error(...) → 错误堆栈从 throw 位置开始记录,便于定位源头
- Promise.reject(new Error(...)) → 堆栈记录的是 Promise.reject 调用处,原始构造位置丢失(除非手动捕获并重抛)
- throw 'msg' 或 Promise.reject('msg') → 都不带堆栈,仅是原始值,调试困难
链式调用中的行为一致性
在 .then() 回调里,两者表现一致:都会让后续 .catch() 捕获到原因。
- Promise.resolve().then(() => { throw new Error('a'); }) → 被 catch 捕获
- Promise.resolve().then(() => Promise.reject(new Error('b'))); → 同样被 catch 捕获
- 但前者堆栈指向 .then 内部,后者指向 Promise.reject 调用点


















