
Async/Await 是 JavaScript 异步编程的革命性特性,它让处理异步操作变得像处理同步代码一样简单直观。作为 Promise 的语法糖,async/await 不仅提高了代码可读性,还大大简化了错误处理流程。 在这篇文章中,我们将深入探讨 async/await 的核心概念、实际应用场景以及常见陷阱,帮助你掌握现代 JavaScript 异步编程的精髓。
1. Async/Await 基础原理
Async/Await 建立在 Promise 之上,通过语法糖的形式让异步代码更易于理解和编写。
// 基本用法:async函数总是返回Promise
async function fetchData() {
// 使用await等待异步操作完成
const response = await fetch('https://api.example.com/data');
const data = await response.json();
return data;
}
// 调用async函数
fetchData()
.then(data => console.log(data))
.catch(error => console.error(error));
async function fetchData() {
// 使用await等待异步操作完成
const response = await fetch('https://api.example.com/data');
const data = await response.json();
return data;
}
// 调用async函数
fetchData()
.then(data => console.log(data))
.catch(error => console.error(error));
调用 async 函数
遇到 await 暂停执行
等待 Promise 解决
恢复执行并返回值
2. 优雅的错误处理
使用 try/catch 结构处理异步错误,使代码更加健壮。
async function getUserData() {
try {
const response = await fetch('/api/user');
if (!response.ok) {
throw new Error('网络请求失败');
}
const user = await response.json();
return user;
} catch (error) {
console.error('获取用户数据失败:', error.message);
// 返回默认值或重新抛出错误
return { name: '访客' };
}
}
try {
const response = await fetch('/api/user');
if (!response.ok) {
throw new Error('网络请求失败');
}
const user = await response.json();
return user;
} catch (error) {
console.error('获取用户数据失败:', error.message);
// 返回默认值或重新抛出错误
return { name: '访客' };
}
}
错误处理流程
错误发生
↓
进入catch块
↓
错误处理逻辑
↓
返回安全值
3. 并行执行多个异步操作
使用 Promise.all 同时执行多个独立异步操作,提高执行效率。
async function loadMultipleResources() {
try {
// 同时发起多个请求
const [user, posts, comments] = await Promise.all([
fetch('/api/user').then(r => r.json()),
fetch('/api/posts').then(r => r.json()),
fetch('/api/comments').then(r => r.json())
]);
console.log('用户:', user);
console.log('文章:', posts);
console.log('评论:', comments);
return { user, posts, comments };
} catch (error) {
console.error('加载资源失败:', error);
}
}
try {
// 同时发起多个请求
const [user, posts, comments] = await Promise.all([
fetch('/api/user').then(r => r.json()),
fetch('/api/posts').then(r => r.json()),
fetch('/api/comments').then(r => r.json())
]);
console.log('用户:', user);
console.log('文章:', posts);
console.log('评论:', comments);
return { user, posts, comments };
} catch (error) {
console.error('加载资源失败:', error);
}
}
用户数据
文章数据
评论数据
↓ 并行加载
全部加载完成
4. 在循环中处理异步操作
正确处理循环中的异步操作,避免常见陷阱。
// 错误做法:顺序执行,效率低下
async function processArraySequential(array) {
for (const item of array) {
await processItem(item); // 每个操作等待前一个完成
}
}
// 正确做法:并行处理
async function processArrayParallel(array) {
// 创建所有promise
const promises = array.map(item => processItem(item));
// 等待所有操作完成
await Promise.all(promises);
}
// 顺序处理但使用async/await
async function processArraySequentialCorrect(array) {
for (const item of array) {
await processItem(item); // 需要顺序执行时使用
}
}
async function processArraySequential(array) {
for (const item of array) {
await processItem(item); // 每个操作等待前一个完成
}
}
// 正确做法:并行处理
async function processArrayParallel(array) {
// 创建所有promise
const promises = array.map(item => processItem(item));
// 等待所有操作完成
await Promise.all(promises);
}
// 顺序处理但使用async/await
async function processArraySequentialCorrect(array) {
for (const item of array) {
await processItem(item); // 需要顺序执行时使用
}
}
循环策略对比
方法 | 执行方式 | 适用场景 |
---|---|---|
顺序执行 | 一个接一个 | 操作有依赖关系 |
并行执行 | 同时执行 | 操作相互独立 |
Promise.allSettled | 并行,不中断 | 需要所有结果 |
5. 高级模式与实践技巧
掌握高级使用模式,提升异步编程能力。
// 1. 异步初始化模式
const initializeApp = (async function() {
const config = await loadConfig();
await connectToDatabase(config.db);
await preloadTemplates();
// 返回初始化完成的应用
return {
start: async function() {
// 应用启动逻辑
}
};
})();
// 使用
initializeApp.then(app => app.start());
// 2. 超时控制
async function fetchWithTimeout(url, timeout = 5000) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
try {
const response = await fetch(url, {
signal: controller.signal
});
return await response.json();
} finally {
clearTimeout(timeoutId);
}
}
const initializeApp = (async function() {
const config = await loadConfig();
await connectToDatabase(config.db);
await preloadTemplates();
// 返回初始化完成的应用
return {
start: async function() {
// 应用启动逻辑
}
};
})();
// 使用
initializeApp.then(app => app.start());
// 2. 超时控制
async function fetchWithTimeout(url, timeout = 5000) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
try {
const response = await fetch(url, {
signal: controller.signal
});
return await response.json();
} finally {
clearTimeout(timeoutId);
}
}
高级技巧
异步初始化
应用启动前完成所有依赖加载
超时控制
防止异步操作无限期挂起
组合模式
多个异步操作组合为单一操作
最佳实践提示
- 总是在 async 函数中使用 try/catch 处理错误
- 避免在顶层模块中使用 await(除非在 ES 模块中)
- 并行独立操作使用 Promise.all 提高性能
- 使用 AbortController 实现超时和取消功能
- 为异步函数添加清晰的前缀(如 fetch, load, get)