欢迎光临
我们一直在努力

Promise的理解与应用

  Promise 你可以把它理解成“一个未来才会给你结果的容器”。你现在先拿到一个 Promise,等异步任务结束后,它要么给你成功结果(resolve),要么给你失败原因(reject)。你再通过 .then/.catch/.finally 来处理后续逻辑。

1)Promise 的三个状态

  • pending:进行中(还没出结果)

  • fulfilled:已成功(resolve)

  • rejected:已失败(reject)

状态一旦从 pending 变成 fulfilled 或 rejected,就“定型”了,不能再改回去。

2)怎么创建一个 Promise

最原始的写法就是

new Promise((resolve, reject) => { … })
const p = new Promise((resolve, reject) => {
const a = 1 + 1;
if (a === 2) resolve("success");
else reject("failed");
});

  • resolve(value):把 Promise 变成 fulfilled,并把 value 传给 .then

  • reject(error):把 Promise 变成 rejected,并把 error 传给 .catch

3)怎么使用 Promise:then / catch / finally

p.then((value) => {
console.log("then:", value); // 当 resolve 被调用时执行
}).catch((err) => {
console.log("catch:", err); // 当 reject 被调用时执行
}).finally(() => {
console.log("finally: always run"); // 不管成功失败都会执行(常用于收尾:关闭 loading 等)
});

  • .then 处理成功

  • .catch 处理失败

  • .finally 不管成功失败都会执行(常用于收尾:关闭 loading 等)

4)链式调用(Promise 的核心价值之一)

.then 可以返回一个新值或一个 Promise,从而形成“链”:

// 链式调用示例
const promiseChain = new Promise((resolve, reject) => {
resolve(2);
});

promiseChain
.then((result) => {
console.log(result); // 2
return result * 2;
})
.then((result) => {
console.log(result); // 4
return result * 2;
})
.then((result) => {
console.log(result); // 8
})
.catch((error) => {
console.log('错误:', error);
});
fetch("/api/user")
.then((r) => r.json())
.then((user) => fetch(`/api/order?uid=${user.id}`))
.then((r) => r.json())
.then((orders) => console.log(orders))
.catch((e) => console.error("error:", e));

规则很重要:

  • 在 .then 里 return 普通值:下一层 .then 直接拿到这个值

  • 在 .then 里 return Promise:下一层 .then 会等待这个 Promise 完成后拿到结果

  • 在任意 .then 里 throw 或返回 Promise.reject(…):会直接跳到最近的 .catch

5)Promise 的进阶用法

a) Promise.all() – 并行执行:全都成功才成功;任何一个失败就失败

const recordVideoOne = new Promise((resolve, reject) => {
resolve('视频1录制完成');
});

const recordVideoTwo = new Promise((resolve, reject) => {
resolve('视频2录制完成');
});

const recordVideoThree = new Promise((resolve, reject) => {
resolve('视频3录制完成');
});

// 同时执行所有 Promise,等全部完成
Promise.all([
recordVideoOne,
recordVideoTwo,
recordVideoThree
]).then((messages) => {
console.log(messages);
// 输出:['视频1录制完成', '视频2录制完成', '视频3录制完成']
});

b) Promise.race() – 竞速执行:谁先完成就用谁(成功或失败都算“先完成”)

// 哪个 Promise 先完成就返回哪个的结果
Promise.race([
recordVideoOne,
recordVideoTwo,
recordVideoThree
]).then((message) => {
console.log(message); // 只输出最快完成的那一个
});

c) Promise.allSettled:不管成功失败都等完,给每个结果的状态

用于“我不想因为一个失败就中断汇总”:

Promise.allSettled([p1, p2]).then((results) => console.log(results));

d) Promise.any:只要有一个成功就成功;全失败才失败

用于“多个镜像源取最快可用的成功结果”。

6)Promise vs 回调函数(Callbacks)

1. 传统回调函数方式(Callback Hell – 回调地狱):

// 第一层:检查用户是否存在
function checkUserExists(userId, onSuccess, onError) {
setTimeout(() => {
if (userId === 'user123') {
console.log('✅ 用户存在');
onSuccess(userId);
} else {
onError('用户不存在');
}
}, 1000);
}

// 第二层:验证密码
function validatePassword(userId, password, onSuccess, onError) {
setTimeout(() => {
if (password === 'correct123') {
console.log('✅ 密码正确');
onSuccess({ userId, token: 'abc123' });
} else {
onError('密码错误');
}
}, 1000);
}

// 第三层:获取用户资料
function getUserProfile(token, onSuccess, onError) {
setTimeout(() => {
if (token === 'abc123') {
console.log('✅ 获取用户资料成功');
onSuccess({
name: '张三',
email: 'zhangsan@example.com',
avatar: 'avatar.jpg'
});
} else {
onError('Token无效');
}
}, 1000);
}

// 使用:典型的回调地狱(Callback Hell)
checkUserExists('user123',
(userId) => {
validatePassword(userId, 'correct123',
(authData) => {
getUserProfile(authData.token,
(profile) => {
console.log('🎉 登录成功!', profile);
// 这里可能还有更多嵌套…
},
(profileError) => {
console.log('❌ 获取资料失败:', profileError);
}
);
},
(passwordError) => {
console.log('❌ 密码验证失败:', passwordError);
}
);
},
(userError) => {
console.log('❌ 用户验证失败:', userError);
}
);

2. 使用 Promise 改进:

// 用 Promise 重写各个函数
function checkUserExistsPromise(userId) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (userId === 'user123') {
console.log('✅ 用户存在');
resolve(userId);
} else {
reject('用户不存在');
}
}, 1000);
});
}

function validatePasswordPromise(userId, password) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (password === 'correct123') {
console.log('✅ 密码正确');
resolve({ userId, token: 'abc123' });
} else {
reject('密码错误');
}
}, 1000);
});
}

function getUserProfilePromise(token) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (token === 'abc123') {
console.log('✅ 获取用户资料成功');
resolve({
name: '张三',
email: 'zhangsan@example.com',
avatar: 'avatar.jpg'
});
} else {
reject('Token无效');
}
}, 1000);
});
}

// 使用 Promise:链式调用,避免嵌套
checkUserExistsPromise('user123')
.then((userId) => {
return validatePasswordPromise(userId, 'correct123');
})
.then((authData) => {
return getUserProfilePromise(authData.token);
})
.then((profile) => {
console.log('🎉 登录成功!', profile);
// 这里可以继续链式调用…
return fetchUserFriends(profile.id);
})
.catch((error) => {
// 统一错误处理
console.log('❌ 登录失败:', error);
});

// 更简洁的写法
checkUserExistsPromise('user123')
.then(userId => validatePasswordPromise(userId, 'correct123'))
.then(authData => getUserProfilePromise(authData.token))
.then(profile => {
console.log('🎉 登录成功!', profile);
})
.catch(error => {
console.log('❌ 登录失败:', error);
});

3. 更复杂的场景:多个并行的 API 请求:

回调地狱版本:

// 获取购物车数据
getCartData((cartData) => {
// 获取用户信息
getUserInfo((userInfo) => {
// 获取商品库存
getProductStock((stockInfo) => {
// 获取优惠券
getCoupons((coupons) => {
// 获取推荐商品
getRecommendations((recommendations) => {
// 5层嵌套!代码越来越难读
renderCheckoutPage(cartData, userInfo, stockInfo, coupons, recommendations);
}, (recError) => {
console.log('推荐商品获取失败', recError);
});
}, (couponError) => {
console.log('优惠券获取失败', couponError);
});
}, (stockError) => {
console.log('库存获取失败', stockError);
});
}, (userError) => {
console.log('用户信息获取失败', userError);
});
}, (cartError) => {
console.log('购物车获取失败', cartError);
});

Promise 版本:

// 并行执行所有请求
Promise.all([
getCartDataPromise(),
getUserInfoPromise(),
getProductStockPromise(),
getCouponsPromise(),
getRecommendationsPromise()
])
.then(([cartData, userInfo, stockInfo, coupons, recommendations]) => {
// 所有数据都准备好了
renderCheckoutPage(cartData, userInfo, stockInfo, coupons, recommendations);
})
.catch((error) => {
// 任何一个请求失败都会到这里
console.log('页面数据获取失败:', error);
});

// 如果需要部分失败也能继续
Promise.allSettled([
getCartDataPromise(),
getUserInfoPromise(),
getProductStockPromise()
])
.then((results) => {
const cartData = results[0].status === 'fulfilled' ? results[0].value : null;
const userInfo = results[1].status === 'fulfilled' ? results[1].value : null;
const stockInfo = results[2].status === 'fulfilled' ? results[2].value : null;

// 即使部分失败也能继续
renderPartialData(cartData, userInfo, stockInfo);
});

4. 现代最佳实践:Async/Await + Promise

async function processPayment(orderId, paymentMethod) {
try {
// 1. 验证订单
const order = await validateOrder(orderId);

// 2. 处理支付
const paymentResult = await processPaymentGateway(paymentMethod, order.total);

// 3. 更新订单状态
await updateOrderStatus(orderId, 'paid', paymentResult.transactionId);

// 4. 发送收据(并行执行,不阻塞)
const sendReceipt = sendReceiptEmail(order.email, paymentResult);

// 5. 更新库存(并行执行,不阻塞)
const updateInventory = updateInventoryAfterPayment(order.items);

// 等待并行任务完成
await Promise.all([sendReceipt, updateInventory]);

return {
success: true,
transactionId: paymentResult.transactionId,
message: '支付成功'
};
} catch (error) {
// 自动捕获所有错误
console.error('支付流程失败:', error);

// 回滚操作
await rollbackPayment(orderId);

return {
success: false,
message: error.message
};
}
}

// 使用
const result = await processPayment('order123', 'credit_card');
if (result.success) {
console.log('🎉 支付成功');
} else {
console.log('❌ 支付失败');
}

7)实战里最常见的坑

  • 在 .then 里忘了 return 导致链断掉

  • 避免 Promise 嵌套:使用链式调用替代嵌套

  • 不要忘记 catch:每个 Promise 链都应该有错误处理

  • 使用 Promise.all 优化:多个独立异步操作应该并行执行

  • 想并发却写成串行(应先创建多个 Promise,再 Promise.all)

  • 在 render/循环里重复创建 Promise(会重复请求/抖动),应该缓存或稳定化

赞(0)
未经允许不得转载:171主机测评 » Promise的理解与应用
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址