Promise 是什么?
简单来说,Promise 是 JavaScript 用来处理异步操作的一个“承诺”。
想象一下:
- 你去餐厅点餐,服务员不会让你干等着,而是给你一个取餐号(Promise),告诉你:“餐好了会通知你”。
- 这个号(Promise)代表未来的结果,可能是成功(拿到餐),也可能是失败(餐卖完了)。
1. 为什么需要 Promise?
在 Promise 之前,JavaScript 用回调函数(Callback)处理异步,比如:
getData(function(data) { // 成功回调
processData(data, function(result) { // 嵌套回调
saveData(result, function() { // 又一层回调
console.log("Done!");
});
});
});
问题:
- 回调地狱(Callback Hell):代码嵌套太深,像“金字塔”,难读难维护。
- 错误处理麻烦:每个回调都要单独处理错误。
👉 Promise 的解决方案:
用 .then()
链式调用,让代码变“扁平”,更接近同步代码的写法。
2. Promise 的三种状态
Promise 就像一个“状态机”,有 3 种状态:
状态 | 说明 | 比喻 |
---|---|---|
Pending | 进行中,还没结果 | “餐还没做好,等着吧” |
Fulfilled | 成功,有结果了(调用 resolve ) | “餐好了,快来拿!” |
Rejected | 失败,出错了(调用 reject ) | “抱歉,餐卖完了” |
⚠️ 注意:
- 状态一旦改变,就不能再变(比如从
fulfilled
变成rejected
是不行的)。 - 如果没监听错误(
.catch()
),控制台会报UnhandledPromiseRejectionWarning
(未处理的 Promise 拒绝)。
3. 基本用法:创建 Promise
const promise = new Promise((resolve, reject) => {
// 这里是异步操作,比如 AJAX 请求、定时器等
if (/* 成功 */) {
resolve("成功的结果"); // 状态变为 fulfilled
} else {
reject("失败的原因"); // 状态变为 rejected
}
});
例子:模拟一个点餐 Promise
function orderFood() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const isSuccess = Math.random() > 0.5; // 50% 概率成功
if (isSuccess) {
resolve("🍔 汉堡做好了!");
} else {
reject("❌ 汉堡卖完了!");
}
}, 2000); // 2秒后出结果
});
}
**4. 使用 Promise:.then()
和 .catch()
**
拿到 Promise 后,用 .then()
处理成功,.catch()
处理失败:
orderFood()
.then((food) => {
console.log(food); // "🍔 汉堡做好了!"
})
.catch((error) => {
console.log(error); // "❌ 汉堡卖完了!"
});
👉 关键点:
.then()
可以链式调用,避免回调地狱。.catch()
会捕获前面所有.then()
里的错误。
链式调用示例:
orderFood()
.then((food) => {
console.log(food);
return "🍟 加一份薯条"; // 返回一个新值,传给下一个 .then()
})
.then((sideDish) => {
console.log(sideDish); // "🍟 加一份薯条"
})
.catch((error) => {
console.log("出错啦:", error);
});
5. 高级用法
(1) Promise.all()
– 等所有 Promise 完成
const p1 = Promise.resolve("任务1");
const p2 = Promise.resolve("任务2");
const p3 = new Promise((resolve) => setTimeout(() => resolve("任务3"), 1000));
Promise.all([p1, p2, p3])
.then((results) => {
console.log(results); // ["任务1", "任务2", "任务3"]
})
.catch((error) => {
console.log("有一个失败了", error);
});
特点:
- 所有 Promise 都成功,才返回结果数组。
- **有一个失败,立即进入
.catch()
**(不会等其他的)。
适用场景:
- 同时发多个请求,等全部完成后处理数据。
(2) Promise.race()
– 谁快用谁
const p1 = new Promise((resolve) => setTimeout(() => resolve("任务1"), 2000));
const p2 = new Promise((resolve) => setTimeout(() => resolve("任务2"), 1000));
Promise.race([p1, p2])
.then((result) => {
console.log(result); // "任务2"(因为 p2 更快)
});
特点:
- 第一个完成的 Promise(无论成功/失败)决定结果。
适用场景:
- 请求超时控制(比如 3 秒内没响应就报错)。
(3) Promise.finally()
– 无论成功失败都执行
orderFood()
.then((food) => console.log(food))
.catch((error) => console.log(error))
.finally(() => {
console.log("无论如何,餐厅关门了");
});
特点:
- 类似
try/catch/finally
,适合清理操作(比如关闭加载动画)。
6. 常见误区
❌ 误区 1:忘记 return
// 错误写法!第二个 then 拿不到 "🍟"
orderFood()
.then((food) => {
console.log(food);
"🍟 加一份薯条"; // 没写 return!
})
.then((sideDish) => {
console.log(sideDish); // undefined
});
✅ 正确写法:
javascript
javascript
复制
.then((food) => {
console.log(food);
return "🍟 加一份薯条"; // 必须 return!
})
❌ 误区 2:错误处理不完整
javascript
javascript
复制
// 错误写法!如果 then 里出错,catch 抓不到
orderFood()
.then((food) => {
throw new Error("吃到虫子了!"); // 这里会报错
})
.catch((error) => {
console.log(error); // 能捕获
});
✅ 正确写法:
确保每个可能出错的地方都有 .catch()
。
7. 总结:Promise 的核心价值
- 解决回调地狱 → 用
.then()
链式调用,代码更清晰。 - 更好的错误处理 → 用
.catch()
统一捕获错误。 - 支持并发控制 →
Promise.all
/Promise.race
管理多个异步任务。 - 更接近同步写法 → 让异步代码更容易理解和维护。
最终比喻
Promise 就像外卖订单:
- 你下单(
new Promise
) - 餐厅接单(
pending
) - 要么成功送到(
resolve
→.then()
) - 要么失败退款(
reject
→.catch()
) - 无论如何,最后清理餐桌(
.finally()
)
有了 Promise,异步代码再也不是“一团乱麻”,而是清晰可控的流程!