定义Promise
想象我们叫了一份外卖(异步任务),Promise 就是一张取餐凭证
- 📦 承诺状态 :记录外卖是
配送中(pending)
、已送达(fulfilled)
还是配送失败(rejected)
- 📝 凭证功能 :凭此证可查询结果(
.then()
取成功)或处理异常(.catch()
取失败)
js
// 创建一份外卖订单(Promise实例)
const takeout = new Promise((resolve, reject) => {
// 厨房做饭(异步操作)
setTimeout(() => {
const isSuccess = Math.random() > 0.3;
isSuccess
? resolve("🍔 汉堡套餐") // 外卖送达
: reject("🚫 配送车坏了"); // 配送失败
}, 2000);
});
用法详解
处理结果:.then()
签收包裹 订单完成后自动通知你取餐
js
takeout.then(food => {
console.log(` 收到:${food}`); // 成功时执行
}).catch(error => {
console.log(` 失败:${error}`); // 失败时执行
});
链式调用:多任务接力配送 解决"回调地狱"(层层嵌套),转为清晰流水线
js
// 传统回调地狱(缩进噩梦)
orderFood(food => {
openBox(() => {
eatFood(() => { ... });
});
});
// Promise链式调用(快递员接力)
orderFood()
.then(food => openBox(food)) // 任务1完成 → 任务2
.then(openedFood => eatFood(openedFood)) // 任务2完成 → 任务3
.catch(error => handleError(error)); // 任一环节失败均捕获
批量管理:集中处理多个订单
方法 | 作用 | 生活案例 |
---|---|---|
Promise.all() |
等所有外卖到齐才通知取餐 | 聚餐订多份餐,齐了才开饭 |
Promise.race() |
任意一份送达就通知(竞速响应) | 急用药品,选最快送达的快递 |
js
// 等所有图片加载完成
const preloadImages = [
loadImg("pic1.jpg"),
loadImg("pic2.jpg")
];
Promise.all(preloadImages)
.then(imgs => console.log(" 所有图片已加载"))
.catch(err => console.log(" 有图片加载失败"));
// 竞速:谁先响应用谁
Promise.race([fetchA(), fetchB()])
.then(firstData => console.log(" 最快结果:", firstData));
Promise 的三大特性
状态不可逆
pending
→fulfilled
(成功)pending
→rejected
(失败)
→ 状态凝固后不可更改(类似外卖送达后不能取消)
错误冒泡机制 链式调用中,任一环节出错都会跳过后续.then()
,直达.catch()
js
step1()
.then(step2) // 若此处出错
.then(step3) // 被跳过
.catch(err => handleAllErrors(err)); // 统一捕获
避免回调地狱 将嵌套异步逻辑转为纵向链式调用,代码更扁平易读
对比传统回调函数
场景 | 回调函数 | Promise |
---|---|---|
多异步任务顺序执行 | 多层嵌套(金字塔缩进) | 链式调用(清晰流水线) |
错误处理 | 需逐层手动判断 | 自动冒泡到 .catch() |
状态管理 | 无统一状态跟踪 | 明确三种状态可追踪 |
Promise 短板
- 无法取消(一旦创建必须执行到底)
- 不提供进度通知(如"外卖还有500米")
一些常用的使用场景
AJAX 请求封装
js
function fetchData(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.onload = () => resolve(xhr.response);
xhr.onerror = () => reject("请求失败");
xhr.send();
});
}
图片批量预加载
js
const loadImage = src => new Promise((resolve, reject) => {
const img = new Image();
img.src = src;
img.onload = resolve;
img.onerror = reject;
});