Promise 和 async/await 完全指南
1. 为什么需要 Promise 和 async/await?
传统回调函数的问题
javascript
// 回调地狱示例
getData(function(a) {
getMoreData(a, function(b) {
getEvenMoreData(b, function(c) {
getEvenEvenMoreData(c, function(d) {
// 处理最终结果
console.log(d);
});
});
});
});
问题:
- 代码难以阅读和维护
- 错误处理困难
- 难以进行流程控制
2. Promise 基础概念
什么是 Promise?
Promise 是一个代表异步操作最终完成或失败的对象。
Promise 的三种状态
javascript
// 状态转换图
Pending(等待) → Fulfilled(成功) → Settled(已敲定)
↘ Rejected(失败) ↗
Promise 基本语法
javascript
// 创建 Promise
const myPromise = new Promise((resolve, reject) => {
// 异步操作
setTimeout(() => {
const success = true;
if (success) {
resolve("操作成功!"); // 成功时调用
} else {
reject("操作失败!"); // 失败时调用
}
}, 1000);
});
// 使用 Promise
myPromise
.then(result => {
console.log("成功:", result);
})
.catch(error => {
console.log("失败:", error);
});
3. Promise 实际应用示例
示例1:模拟网络请求
javascript
// 模拟 API 请求
function fetchUserData(userId) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (userId > 0) {
resolve({
id: userId,
name: `用户${userId}`,
email: `user${userId}@example.com`
});
} else {
reject(new Error("无效的用户ID"));
}
}, 1000);
});
}
// 使用 Promise
fetchUserData(1)
.then(user => {
console.log("获取用户信息:", user);
return fetchUserData(2); // 链式调用
})
.then(user2 => {
console.log("获取第二个用户:", user2);
})
.catch(error => {
console.error("错误:", error.message);
});
示例2:Promise.all 并行处理
javascript
// 同时获取多个用户信息
const promises = [
fetchUserData(1),
fetchUserData(2),
fetchUserData(3)
];
Promise.all(promises)
.then(users => {
console.log("所有用户信息:", users);
})
.catch(error => {
console.error("其中一个请求失败:", error);
});
4. async/await 语法
基本概念
async/await
是 Promise 的语法糖,让异步代码看起来像同步代码。
基本用法
javascript
// async 函数
async function getUserInfo(userId) {
try {
// await 等待 Promise 完成
const user = await fetchUserData(userId);
console.log("用户信息:", user);
return user;
} catch (error) {
console.error("获取用户失败:", error.message);
throw error; // 重新抛出错误
}
}
// 调用 async 函数
getUserInfo(1).then(user => {
console.log("最终结果:", user);
});
实际应用示例
javascript
// 顺序执行多个异步操作
async function processUsers() {
try {
console.log("开始获取用户...");
const user1 = await fetchUserData(1);
console.log("用户1:", user1);
const user2 = await fetchUserData(2);
console.log("用户2:", user2);
return [user1, user2];
} catch (error) {
console.error("处理用户时出错:", error);
throw error;
}
}
// 并行执行多个异步操作
async function processUsersParallel() {
try {
console.log("并行获取用户...");
// 同时发起多个请求
const [user1, user2, user3] = await Promise.all([
fetchUserData(1),
fetchUserData(2),
fetchUserData(3)
]);
console.log("所有用户:", user1, user2, user3);
return [user1, user2, user3];
} catch (error) {
console.error("并行处理失败:", error);
throw error;
}
}
5. 完整实战示例
javascript
// 模拟真实的 API 调用场景
class ApiService {
// 模拟 HTTP 请求
static request(url, data = {}) {
return new Promise((resolve, reject) => {
setTimeout(() => {
// 模拟 80% 成功率
if (Math.random() > 0.2) {
resolve({
success: true,
data: { ...data, id: Date.now(), timestamp: new Date() },
message: "请求成功"
});
} else {
reject(new Error("网络请求失败"));
}
}, Math.random() * 1000 + 500); // 随机延迟 500-1500ms
});
}
}
// 使用 Promise 的方式
function fetchUserWithPromise(userId) {
return ApiService.request(`/api/users/${userId}`, { userId })
.then(response => {
console.log(`Promise方式 - 用户${userId}获取成功`);
return response.data;
})
.catch(error => {
console.error(`Promise方式 - 获取用户${userId}失败:`, error.message);
throw error;
});
}
// 使用 async/await 的方式
async function fetchUserWithAsync(userId) {
try {
const response = await ApiService.request(`/api/users/${userId}`, { userId });
console.log(`Async方式 - 用户${userId}获取成功`);
return response.data;
} catch (error) {
console.error(`Async方式 - 获取用户${userId}失败:`, error.message);
throw error;
}
}
// 实际使用示例
async function main() {
console.log("=== Promise 方式 ===");
try {
const user1 = await fetchUserWithPromise(1);
const user2 = await fetchUserWithPromise(2);
console.log("Promise结果:", user1, user2);
} catch (error) {
console.error("Promise流程出错:", error.message);
}
console.log("\n=== Async/Await 方式 ===");
try {
const user3 = await fetchUserWithAsync(3);
const user4 = await fetchUserWithAsync(4);
console.log("Async结果:", user3, user4);
} catch (error) {
console.error("Async流程出错:", error.message);
}
console.log("\n=== 并行处理 ===");
try {
const results = await Promise.all([
fetchUserWithAsync(5),
fetchUserWithAsync(6),
fetchUserWithAsync(7)
]);
console.log("并行结果:", results);
} catch (error) {
console.error("并行处理出错:", error.message);
}
}
// 运行示例
main();
6. 重要注意事项
错误处理
javascript
// ❌ 错误的错误处理
async function badExample() {
const user = await fetchUserData(1);
const posts = await fetchUserPosts(user.id); // 如果这里出错,下面的代码不会执行
return { user, posts };
}
// ✅ 正确的错误处理
async function goodExample() {
try {
const user = await fetchUserData(1);
const posts = await fetchUserPosts(user.id);
return { user, posts };
} catch (error) {
console.error("操作失败:", error);
// 可以选择重新抛出或返回默认值
return { user: null, posts: [] };
}
}
性能优化
javascript
// ❌ 顺序执行(慢)
async function slowWay() {
const user = await fetchUserData(1); // 等待 1 秒
const posts = await fetchUserPosts(1); // 再等待 1 秒
const comments = await fetchComments(1); // 再等待 1 秒
// 总共 3 秒
}
// ✅ 并行执行(快)
async function fastWay() {
// 同时发起所有请求
const [user, posts, comments] = await Promise.all([
fetchUserData(1),
fetchUserPosts(1),
fetchComments(1)
]);
// 总共 1 秒
}
避免常见陷阱
javascript
// ❌ 不要在循环中使用 await(会变成顺序执行)
async function badLoop() {
const results = [];
for (let i = 1; i <= 3; i++) {
const result = await fetchUserData(i); // 一个接一个执行
results.push(result);
}
return results;
}
// ✅ 在循环中使用 Promise.all 实现并行
async function goodLoop() {
const promises = [];
for (let i = 1; i <= 3; i++) {
promises.push(fetchUserData(i)); // 同时发起所有请求
}
const results = await Promise.all(promises);
return results;
}
7. 总结
Promise vs async/await 选择指南
使用 Promise 的场景:
- 简单的异步操作
- 需要链式调用
- 与旧代码兼容
使用 async/await 的场景:
- 复杂的异步逻辑
- 需要错误处理
- 代码可读性要求高
最佳实践
- 总是处理错误 - 使用
.catch()
或try/catch
- 合理使用并行 - 用
Promise.all()
优化性能 - 避免回调地狱 - 优先使用 Promise 或 async/await
- 保持一致性 - 在项目中统一使用一种风格
通过掌握这些概念和技巧,你就能轻松处理 JavaScript 中的异步编程了!