Promise 入门:告别回调地狱的第一步

为什么 JavaScript 需要 Promise?它解决了什么问题?小明带你从回调地狱的深渊爬出来,理解 Promise 的核心概念、链式调用以及错误处理。

10 分钟阅读
小明

Promise 入门:告别回调地狱的第一步

你一定写过这样的代码:

getUser(userId, function(user) {
  getOrders(user.id, function(orders) {
    getOrderDetails(orders[0].id, function(details) {
      console.log(details);
      // 如果还有下一层呢?
    });
  });
});

一层套一层,越写越深,代码最终变成了一个向右倾斜的金字塔。这就是传说中的回调地狱(Callback Hell)

今天,小明就带你认识 JavaScript 异步编程的第一个"救世主"——Promise


一、什么是 Promise?

Promise 是一个代表异步操作最终完成或失败的对象。它就像一张"凭证",承诺你将来会得到一个结果。

一个 Promise 有三种状态:

  1. Pending(进行中):初始状态,操作还没完成。
  2. Fulfilled(已成功):操作成功完成。
  3. Rejected(已失败):操作失败。

一旦状态改变,就不会再变了。 这是 Promise 最重要的特性。


二、创建一个 Promise

const myPromise = new Promise((resolve, reject) => {
  // 模拟一个异步操作,比如网络请求
  setTimeout(() => {
    const success = true;
    if (success) {
      resolve('操作成功!'); // 成功时调用 resolve
    } else {
      reject('操作失败!');  // 失败时调用 reject
    }
  }, 1000);
});

resolvereject 是两个函数,分别用来把 Promise 的状态从 Pending 改变成 Fulfilled 或 Rejected。


三、使用 Promise:.then() 和 .catch()

创建了 Promise 之后,怎么获取它的结果呢?

myPromise
  .then(result => {
    console.log(result); // '操作成功!'
  })
  .catch(error => {
    console.error(error);
  });
  • .then() 接收成功后的回调。
  • .catch() 接收失败后的回调。

四、链式调用:Promise 的精髓

这才是 Promise 真正解决回调地狱的地方。

.then() 会返回一个新的 Promise,所以你可以无限链接下去,代码不再是金字塔,而是一条直线:

getUser(userId)
  .then(user => getOrders(user.id))
  .then(orders => getOrderDetails(orders[0].id))
  .then(details => {
    console.log(details);
  })
  .catch(error => {
    // 任何一步出错,都会在这里被捕获
    console.error('出错了:', error);
  });

看看这代码,是不是清爽多了?


五、Promise.all 和 Promise.race

5.1 Promise.all:全部成功才成功

当你需要同时发起多个请求,并且等所有请求都完成后再执行下一步:

Promise.all([getUser(1), getUser(2), getUser(3)])
  .then(results => {
    console.log(results); // [user1, user2, user3]
  });

注意:只要有一个 Promise 失败,整个 Promise.all 就会立即失败。

5.2 Promise.race:谁快用谁

只取最先完成的那个结果:

Promise.race([fetchFromServer1(), fetchFromServer2()])
  .then(result => {
    console.log('最快的服务器返回了:', result);
  });

六、常见错误

6.1 忘记 return

.then() 链中,如果你想把一个值传递给下一个 .then(),必须 return

// ❌ 错误
.then(user => {
  getOrders(user.id); // 忘记 return,下一个 then 收到的是 undefined
})

// ✅ 正确
.then(user => {
  return getOrders(user.id);
})

6.2 不捕获错误

没有 .catch() 的 Promise 链,如果出错,错误会被静默吞掉,非常难排查。


总结

  1. Promise 是处理异步操作的标准方式。
  2. 三种状态:Pending → Fulfilled / Rejected,不可逆。
  3. 链式调用 (.then().then()) 是解决回调地狱的核心。
  4. 错误处理:链末尾一定要加 .catch()

小明建议: Promise 是 async/await 的基石。如果你想写出优雅的异步代码,必须先把 Promise 吃透。不要跳过这一步直接学 async/await,那样只是"会用",而不是"理解"。


"Promise 的本质是什么?" "是对未来的承诺。成功就兑现,失败就赔偿。" —— 小明

最后,送你一个冷笑话: Promise 问程序员:"你相信我吗?" 程序员说:"我给你加个 .catch(),如果你骗我,我就知道了。" Promise 叹了口气:"你这不叫信任,你这叫'验证驱动开发'。"