切换主题
async/await
async/await 是 JavaScript 中处理异步操作的一种更优雅的方式,它建立在 Promise 之上,使异步代码看起来和同步代码一样。
基本概念
1. async 函数
async 函数总是返回一个 Promise。
javascript
// 基本语法
async function fetchData() {
return '数据';
}
// 等同于
function fetchData() {
return Promise.resolve('数据');
}
// 使用
fetchData().then(data => console.log(data));
2. await 操作符
await 只能在 async 函数内部使用,它会暂停函数的执行,直到 Promise 完成。
javascript
async function fetchUserData() {
const response = await fetch('https://api.example.com/user');
const data = await response.json();
return data;
}
错误处理
1. try/catch
javascript
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
return data;
} catch (error) {
console.error('获取数据失败:', error);
throw error;
}
}
2. 错误传播
javascript
async function processData() {
try {
const data = await fetchData();
return data;
} catch (error) {
// 处理错误
return '默认数据';
}
}
并行执行
1. Promise.all 与 await
javascript
async function fetchMultipleData() {
const [users, posts, comments] = await Promise.all([
fetchUsers(),
fetchPosts(),
fetchComments()
]);
return { users, posts, comments };
}
2. 顺序执行 vs 并行执行
javascript
// 顺序执行
async function sequential() {
const user = await fetchUser();
const posts = await fetchPosts(user.id);
const comments = await fetchComments(posts[0].id);
return { user, posts, comments };
}
// 并行执行
async function parallel() {
const [user, posts, comments] = await Promise.all([
fetchUser(),
fetchPosts(),
fetchComments()
]);
return { user, posts, comments };
}
高级用法
1. 异步迭代器
javascript
async function* asyncGenerator() {
yield await Promise.resolve(1);
yield await Promise.resolve(2);
yield await Promise.resolve(3);
}
async function iterate() {
for await (const num of asyncGenerator()) {
console.log(num);
}
}
2. 异步类方法
javascript
class DataFetcher {
async fetchData() {
const response = await fetch('https://api.example.com/data');
return response.json();
}
static async fetchStaticData() {
const response = await fetch('https://api.example.com/static');
return response.json();
}
}
常见陷阱
1. 在循环中使用 await
javascript
// 不好的做法
async function processItems(items) {
for (const item of items) {
await processItem(item); // 顺序执行
}
}
// 好的做法
async function processItems(items) {
await Promise.all(items.map(item => processItem(item))); // 并行执行
}
2. 忘记 await
javascript
// 不好的做法
async function fetchData() {
const promise = fetch('https://api.example.com/data');
const data = promise.json(); // 错误:promise 还未解析
return data;
}
// 好的做法
async function fetchData() {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
return data;
}
3. 错误处理不完整
javascript
// 不好的做法
async function fetchData() {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
return data;
}
// 好的做法
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error('获取数据失败:', error);
throw error;
}
}
性能优化
1. 避免不必要的 await
javascript
// 不好的做法
async function processData() {
const data = await fetchData();
const processed = await processData(data);
return processed;
}
// 好的做法
async function processData() {
const data = await fetchData();
return processData(data); // 如果 processData 是同步的,不需要 await
}
2. 并行请求优化
javascript
// 不好的做法
async function fetchUserData(userId) {
const user = await fetchUser(userId);
const posts = await fetchUserPosts(userId);
const comments = await fetchUserComments(userId);
return { user, posts, comments };
}
// 好的做法
async function fetchUserData(userId) {
const [user, posts, comments] = await Promise.all([
fetchUser(userId),
fetchUserPosts(userId),
fetchUserComments(userId)
]);
return { user, posts, comments };
}
最佳实践
1. 函数命名
javascript
// 好的命名
async function fetchUserData() { }
async function processPayment() { }
async function validateForm() { }
// 不好的命名
async function getData() { }
async function doStuff() { }
async function handle() { }
2. 错误处理
javascript
// 好的错误处理
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('获取数据失败:', error);
throw new Error('数据获取失败,请稍后重试');
}
}
3. 超时处理
javascript
async function fetchWithTimeout(url, timeout = 5000) {
const controller = new AbortController();
const id = setTimeout(() => controller.abort(), timeout);
try {
const response = await fetch(url, {
signal: controller.signal
});
clearTimeout(id);
return response;
} catch (error) {
clearTimeout(id);
throw error;
}
}
总结
- async/await 使异步代码更易读和维护
- 正确处理错误和异常情况
- 合理使用并行执行提高性能
- 避免常见陷阱和错误
- 遵循最佳实践和命名规范
- 注意性能优化和资源使用
- 使用适当的错误处理和超时机制