JavaScript 里的 Promise 到底应该如何理解?
最简单、最不容易误解的理解方式是下面这三句话:
- Promise 是一个“未来会给出结果的承诺”
- 这个承诺只有三种最终状态:等待中 → 成功(fulfilled) 或 失败(rejected),而且一旦成功或失败就不可逆
- Promise 的真正价值在于:它把“异步操作”从回调地狱里解放出来,变成了可链式、可组合、可并行、可错误统一的“值”
用生活中的比喻来理解(最推荐的入门视角)
把 Promise 想象成“外卖订单”:
| 现实中的外卖订单 | 对应到 Promise | 关键点说明 |
|---|---|---|
| 你下单了 | new Promise(...) 创建了一个 promise | 订单已经存在,但饭还没到 |
| 商家正在做饭 / 骑手在路上 | promise 处于 pending(等待中) | 目前还拿不到结果 |
| 骑手把饭送到你门口 | resolve(饭) → fulfilled | 成功了,拿到了你想要的东西 |
| 商家说没菜了 / 骑手摔了送不了 | reject(原因) → rejected | 失败了,告诉你为什么 |
| 送到或取消后,订单状态不再变 | 状态一旦变为 fulfilled 或 rejected 就不可逆 | 非常重要!不会反复送也不会反复取消 |
| 你可以告诉朋友“饭到了叫我” | .then() 注册成功回调 | “到了就给我打电话” |
| 你也可以说“送不了也告诉我” | .catch() 或 .then(…, onRejected) | “送不了也要通知我” |
| 不管成功失败都要给小费 | .finally() | “不管怎样都要付配送费” |
Promise 最核心的四件事(必须记住)
- Promise 本身是同步创建的,但它的状态变化是异步的
console.log(1);
const p = new Promise((resolve) => {
console.log(2);
setTimeout(() => {
resolve(3);
console.log(4);
}, 0);
});
p.then(() => console.log(5));
console.log(6);
// 输出顺序:1 → 2 → 6 → 5 → 4
- .then() 永远返回一个新的 Promise(链式调用的根本原因)
fetch(url)
.then(res => res.json()) // 返回一个新的 promise
.then(data => console.log(data)) // 又返回一个新的 promise
.catch(err => console.error(err));
- 错误会穿透所有 .then() 直到被 .catch() 捕获(类似 try-catch 的错误冒泡)
Promise.resolve(1)
.then(() => { throw new Error("炸了") })
.then(() => console.log("不会执行"))
.catch(err => console.log(err.message)); // → 炸了
- Promise.all / allSettled / any / race 是并行处理的利器 方法 特点 只要其中一个… 结果状态取决于… 典型使用场景 Promise.all 最常用 失败 → 整体失败 全部成功才成功 所有图片/接口都必须加载成功 allSettled 无论成功失败都等全部完成 不会短路 永远 fulfilled 批量操作,想知道每个结果 any 第一个成功的就算成功(ES2021) 第一个 fulfilled 就成功 全部失败才失败 并发请求,只要有一个成功即可 race 谁先完成(成功或失败)谁赢 第一个 settled 就结束 跟随最快那个的状态 超时控制、竞速、取最快响应
2025–2026 年最推荐的现代写法(async/await + try-catch)
// 推荐写法(清晰、可读性高、容易调试)
async function fetchUserData(userId) {
try {
const res = await fetch(`/api/users/${userId}`);
if (!res.ok) {
throw new Error(`HTTP ${res.status}`);
}
const data = await res.json();
const profile = await fetchProfile(data.profileId);
return { user: data, profile };
}
catch (err) {
console.error("获取用户数据失败:", err);
throw err; // 可以继续向上抛,也可以在这里处理降级逻辑
}
finally {
// 无论成功失败都会执行(关闭 loading、释放资源等)
hideLoading();
}
}
总结:一句话记住 Promise 的本质
Promise 不是用来“做异步”的,而是用来“管理异步结果”的。
它把原本杂乱无章的回调,变成了:
- 可链式调用
- 可并行处理
- 可统一错误处理
- 可等待多个任务
- 状态明确、不可逆的“异步值”
一旦你把 Promise 理解成“带有状态的未来值”,而不是“一种特殊的回调”,你就真正懂了。
有具体哪一段代码或哪种业务场景的 Promise 写法让你困惑吗?可以贴出来,我帮你改成最清晰的写法。