使用 async/await
处理异步操作:详细讲解与项目示例
在现代 JavaScript 开发中,处理异步操作是非常常见的。过去,开发者主要使用回调函数或 Promise
来处理异步任务,但随着 ES2017 引入的 async/await
语法,异步代码的编写变得更加简洁和易于理解。本文将通过实际的项目代码示例,讲解如何使用 async/await
来处理异步操作。
目录
-
什么是
async/await
?- 1.1
async
关键字 - 1.2
await
关键字 - 1.3
async/await
与Promise
的关系
- 1.1
-
基本语法示例
- 2.1 使用
async
函数 - 2.2 使用
await
等待异步操作
- 2.1 使用
-
async/await
与错误处理- 3.1 使用
try...catch
捕获错误 - 3.2 异常传播
- 3.1 使用
-
实际项目示例
- 4.1 简单的 API 请求示例
- 4.2 并发请求的示例
- 4.3 按顺序执行多个异步操作
-
性能优化与注意事项
- 5.1 异步操作的串行与并行
- 5.2 异步操作的超时处理
1. 什么是 async/await
?
1.1 async
关键字
async
用于定义一个异步函数,函数的返回值总是一个 Promise
对象。如果函数内部有异步操作,async
会使得我们可以使用 await
等待异步操作的结果。
async function myAsyncFunction() {
return "Hello, Async!";
}
myAsyncFunction().then(result => console.log(result)); // 输出:Hello, Async!
1.2 await
关键字
await
用于等待 Promise
对象的结果。它只能在 async
函数内部使用。如果你将 await
用于一个异步操作,它会暂停函数的执行,直到异步操作完成,返回其结果。
async function example() {
const result = await new Promise(resolve => setTimeout(() => resolve("Hello, Await!"), 1000));
console.log(result); // 输出:Hello, Await!
}
example();
1.3 async/await
与 Promise
的关系
async/await
本质上是基于 Promise
的语法糖,它使得异步代码看起来更像同步代码。
// 使用 Promise
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => resolve('Data fetched'), 1000);
});
}
fetchData().then(data => console.log(data)); // 输出:Data fetched
// 使用 async/await
async function fetchDataAsync() {
const data = await fetchData();
console.log(data); // 输出:Data fetched
}
fetchDataAsync();
2. 基本语法示例
2.1 使用 async
函数
async
函数总是返回一个 Promise
,即使函数内部没有显式的 return
语句,它也会隐式地返回一个 Promise
。
async function greet() {
return "Hello, world!";
}
greet().then(result => console.log(result)); // 输出:Hello, world!
2.2 使用 await
等待异步操作
await
用于等待一个 Promise
对象。它会暂停当前函数的执行,直到 Promise
完成并返回结果。
async function fetchUserData() {
const response = await fetch("https://jsonplaceholder.typicode.com/users/1");
const userData = await response.json();
return userData;
}
fetchUserData().then(data => console.log(data)); // 输出:用户数据
3. async/await
与错误处理
3.1 使用 try...catch
捕获错误
async/await
使得错误处理更加简洁。你可以使用 try...catch
来捕获异步操作中的错误。
async function fetchData() {
try {
const response = await fetch("https://jsonplaceholder.typicode.com/users/1");
const data = await response.json();
return data;
} catch (error) {
console.error("Error fetching data:", error);
}
}
fetchData();
3.2 异常传播
如果在 async
函数中抛出异常,返回的 Promise
会变成拒绝状态(rejected)。
async function errorExample() {
throw new Error("Something went wrong");
}
errorExample().catch(error => console.log(error.message)); // 输出:Something went wrong
4. 实际项目示例
4.1 简单的 API 请求示例
在实际项目中,经常需要从 API 获取数据。使用 async/await
可以让代码更加简洁和易于理解。
async function getPosts() {
try {
const response = await fetch("https://jsonplaceholder.typicode.com/posts");
const posts = await response.json();
console.log(posts);
} catch (error) {
console.error("Error fetching posts:", error);
}
}
getPosts();
4.2 并发请求的示例
有时我们需要同时发起多个请求,Promise.all
可以与 async/await
一起使用来并发处理多个异步任务。
async function fetchUserAndPosts() {
try {
const [userResponse, postsResponse] = await Promise.all([
fetch("https://jsonplaceholder.typicode.com/users/1"),
fetch("https://jsonplaceholder.typicode.com/posts")
]);
const user = await userResponse.json();
const posts = await postsResponse.json();
console.log("User:", user);
console.log("Posts:", posts);
} catch (error) {
console.error("Error fetching data:", error);
}
}
fetchUserAndPosts();
4.3 按顺序执行多个异步操作
有时候异步操作之间是有顺序依赖的。在这种情况下,你可以直接按照顺序使用 await
来处理每个操作。
async function processOrder() {
const payment = await processPayment();
console.log("Payment Successful:", payment);
const shipment = await shipOrder();
console.log("Order Shipped:", shipment);
const delivery = await deliverOrder();
console.log("Order Delivered:", delivery);
}
async function processPayment() {
return new Promise(resolve => setTimeout(() => resolve("Payment Processed"), 1000));
}
async function shipOrder() {
return new Promise(resolve => setTimeout(() => resolve("Order Shipped"), 1500));
}
async function deliverOrder() {
return new Promise(resolve => setTimeout(() => resolve("Order Delivered"), 2000));
}
processOrder();
5. 性能优化与注意事项
5.1 异步操作的串行与并行
在处理多个异步任务时,有时我们需要串行执行任务,而有时则希望并行执行任务以提高性能。需要根据具体需求来选择。
- 串行:每个异步操作都必须等上一个完成后才能执行。
- 并行:多个异步操作可以同时执行,
Promise.all
或Promise.allSettled
等方法可以帮助我们实现并行。
5.2 异步操作的超时处理
在某些情况下,异步操作可能会超时。可以通过 setTimeout
和 Promise.race
来实现超时控制。
async function fetchDataWithTimeout() {
const timeout = new Promise((_, reject) => setTimeout(() => reject("Request Timeout"), 5000));
const fetchData = fetch("https://jsonplaceholder.typicode.com/users/1");
try {
const response = await Promise.race([fetchData, timeout]);
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}
}
fetchDataWithTimeout();
总结
async/await
使异步代码看起来更像同步代码,简化了处理异步操作的逻辑。- 使用
async
定义异步函数,await
等待异步操作的结果。 async/await
与Promise
密切相关,但语法更简洁。- 错误处理方面,可以使用
try...catch
来捕获异常。 - 在实际项目中,
async/await
可以帮助我们更高效地处理 API 请求、并发操作等异步任务。
通过灵活运用 async/await
,你可以编写更加简洁、易读且高效的异步代码。