为什么需要 Promise?
在早期的 JavaScript 异步编程中,我们经常会写出这样的代码:
getUser((user) => {
getId(user.id, (id) => {
sendEmail(id, (res) => {
console.log('发送成功')
})
})
})
每一步都依赖上一步的返回结果,函数层层嵌套、结构混乱,这种情况被称为 回调地狱(Callback Hell) 。
为了让异步逻辑更清晰,ES6 引入了 Promise。
一、Promise 是什么?
Promise 是 JavaScript 中用于管理异步任务状态的对象。
你可以把它理解为:“一个承诺未来会给你结果的任务”。
let p = new Promise((resolve, reject) => {
// 异步操作
})
Promise 构造函数接收一个回调函数,该函数有两个参数:
- resolve:异步任务成功时调用;
- reject:异步任务失败时调用。
Promise 实例拥有两个核心属性:
state:状态(pending / fulfilled / rejected)result:结果(resolve 或 reject 传递的值)
二、Promise 的三种状态
| 状态 | 含义 | 改变方式 |
|---|---|---|
| pending | 进行中 | 初始状态 |
| fulfilled | 成功完成 | 调用 resolve() |
| rejected | 失败拒绝 | 调用 reject() |
状态一旦从 pending 变为 fulfilled 或 rejected,就不可逆。
let p = new Promise((resolve, reject) => {
resolve('成功') // 状态:fulfilled
reject('失败') // 无效,状态已锁定
})
三、Promise 的结果传递
resolve() 和 reject() 的参数决定 Promise 的结果值,
而 then() 的返回值又决定了下一个 Promise 的状态。
可以理解为:
resolve 负责“给出答案”,then 负责“传递答案”。
let p = new Promise((resolve, reject) => {
resolve("success")
})
此时:
- Promise 状态:fulfilled
- result 值:
"success"
🔹 参数类型影响状态传递
| 返回值类型 | 效果 | 说明 |
|---|---|---|
| 普通值 | 下一个 then 收到该值 | 最常见情况 |
| Promise 对象 | 外层状态由内层 Promise 决定 | 实现状态传导 |
| 实现了 then() 的对象(thenable) | 状态由其 then() 返回值决定 | 遵循 Promise/A+ 规范 |
| 抛出错误 | 下一个 catch 捕获 | 等价于 reject |
示例一:返回普通值
Promise.resolve(1)
.then((res) => res + 1)
.then((res) => console.log(res)) // 2
示例二:返回 Promise
new Promise((resolve) => {
resolve(1)
})
.then((res) => {
return new Promise((resolve) => {
setTimeout(() => resolve(res + 1), 1000)
})
})
.then((res) => console.log(res)) // 2(延迟1秒输出)
示例三:返回 thenable 对象
Promise.resolve()
.then(() => ({
then(resolve) {
resolve("thenable resolved")
}
}))
.then(console.log) // thenable resolved
这类对象只要实现了 then() 方法,也会被当作 Promise 处理。
四、then() 方法
then() 用于处理 Promise 的结果。
let p = new Promise((resolve, reject) => {
resolve("success")
})
p.then(
(value) => console.log("成功:", value),
(err) => console.log("失败:", err)
)
特性说明:
- 接收两个回调函数:第一个处理成功结果,第二个处理失败;
- 返回一个新的 Promise(初始状态为 pending);
- 可以链式调用,替代嵌套回调。
getUser()
.then(getId)
.then(sendEmail)
.then(() => console.log("邮件发送成功"))
.catch(console.error)
链式 then() 的执行依赖于上一个 Promise 状态的变化。
如果前一步是 pending,then() 不会立即执行。
此外:
- 在then()中return一个普通值,则无论执行的是哪一个回调,返回的Promise状态都为fulfiled
- 在 then() 中 return 值 → 下一个 then() 的输入;
- 在 then() 中抛错 → 状态变为 rejected;
- 在 then() 中 return Promise → 下一个状态由内部 Promise 决定。
五、catch() 方法
catch() 用于捕获 Promise 链中的错误。
let p = new Promise((resolve, reject) => {
reject("出错了")
})
p.catch((err) => {
console.log("失败:", err)
})
catch() 触发的两种情况:
- Promise 被 reject;
- then() 中出现运行错误。
标准写法:
new Promise((resolve, reject) => {
// 异步任务
})
.then((res) => {
// 成功逻辑
})
.catch((err) => {
// 错误处理
})
六、总结
- Promise 通过状态管理异步流程,避免回调地狱。
- 状态改变不可逆,结果由 resolve / reject 控制。
- then() 返回新的 Promise,可实现链式调用。
- 参数类型决定状态传导:普通值、Promise、thenable、异常。
- catch() 统一处理错误,使异步代码更具可读性与健壮性。
✦ 一句话理解
你可以把 Promise 理解为一个“容器” , 它在创建时就被“封装”进了一段可能需要时间的操作(例如异步请求、定时任务、文件读取等)。 当操作完成后,这个容器会:
- 装入一个结果值(成功或失败);
- 锁定状态,不能再被修改;
- 供外部通过
.then()或.catch()来提取结果。