async函数中try/catch捕获的即是promise.reject(reason)中的原始reason值,不包装、不转换;无论字符串、error实例或对象均原样接收,但仅error实例自带stack便于调试。

在 async 函数中,try/catch 捕获的是 Promise 被 reject 时传入的值,这个值就是原始 reject 原因——它不经过任何“包装”,也不隐式转换。关键在于:你拿到的就是 Promise.reject(reason) 中那个 reason,无需额外解包。
reject 的值就是 catch 到的值
Promise 的 reject 行为不会改变传入值的类型或结构。无论你 reject 一个字符串、Error 实例、对象,还是 undefined,catch 或 async 函数的 try/catch 都原样接住:
-
Promise.reject("network failed")→catch(e)中e === "network failed" -
Promise.reject(new TypeError("invalid input"))→e就是那个TypeError实例,具备stack、message等属性 -
Promise.reject({ code: 500, detail: "timeout" })→e就是该对象,可直接访问e.code
避免常见误解:不是所有异常都自动变成 Error
async 函数内部抛出非 Error 值(如 throw "oops")时,JavaScript 不会自动封装成 Error 对象。这和同步代码一致:catch 拿到的仍是字符串字面量。若需统一处理,建议显式构造 Error:
- 推荐:
throw new Error("user not found")—— 便于日志、堆栈追踪 - 不推荐:
throw "user not found"—— 类型弱,无堆栈,调试困难 - 注意:
reject("oops")和throw "oops"在 async 函数中效果等价,但语义不同:前者是主动拒绝 Promise,后者是同步抛错并被隐式转为 reject
捕获链式 Promise 的原始原因
当 async 函数返回一个 Promise(例如调用另一个 async 函数或 fetch()),错误会自然冒泡。只要没在中间 .catch() 吞掉,最终 try/catch 拿到的仍是源头 reject 的值:
async function api() { return fetch("/data").then(r => r.json()); }- 若
fetch失败,fetch()返回的 Promise 被 reject(值为TypeError),api()的返回 Promise 也以同样TypeError被 reject - 外层
await api()的catch拿到的,就是那个原始TypeError,不是包装后的 PromiseRejectionEvent
需要原始堆栈?确保 Error 实例被 reject
如果想保留完整的错误位置信息,必须让 reject 的值是一个带有 stack 的 Error 实例:
- 正确:
Promise.reject(new Error("DB timeout"))——stack包含创建位置 - 错误:
Promise.reject("DB timeout")—— 字符串无stack,无法定位来源 - 补充:在
catch中可手动补全堆栈(如new Error(e + "")),但丢失原始位置,仅作兜底











