JS筑基(三)-关于Promise

29 阅读3分钟

为什么需要 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() 触发的两种情况:

  1. Promise 被 reject;
  2. then() 中出现运行错误。

标准写法:

new Promise((resolve, reject) => {
  // 异步任务
})
  .then((res) => {
    // 成功逻辑
  })
  .catch((err) => {
    // 错误处理
  })

六、总结

  • Promise 通过状态管理异步流程,避免回调地狱。
  • 状态改变不可逆,结果由 resolve / reject 控制。
  • then() 返回新的 Promise,可实现链式调用。
  • 参数类型决定状态传导:普通值、Promise、thenable、异常。
  • catch() 统一处理错误,使异步代码更具可读性与健壮性。

✦ 一句话理解

你可以把 Promise 理解为一个“容器” , 它在创建时就被“封装”进了一段可能需要时间的操作(例如异步请求、定时任务、文件读取等)。 当操作完成后,这个容器会:

  • 装入一个结果值(成功或失败);
  • 锁定状态,不能再被修改;
  • 供外部通过 .then().catch() 来提取结果。