async/await 是ES2017(ES8)引入的用于处理异步操作的语法糖,基于Promise实现。它使得异步代码看起来像同步代码,从而提高了代码的可读性和可维护性。以下是对 async/await 的详细讲解。
基本语法
async 函数
在一个函数前加上 async 关键字,使其成为一个 async 函数。一个 async 函数总是返回一个 Promise 对象。如果函数返回一个非 Promise 的值,该值会被自动封装在一个 Promise.resolve 中。
async function foo() {
return 42;
}
foo().then(result => {
console.log(result); // 输出 42
});
await 关键字
await 关键字只能在 async 函数中使用。它会暂停 async 函数的执行,等待一个 Promise 对象的解决(或拒绝),然后继续执行函数,并返回 Promise 解决的值。如果等待的不是 Promise 对象,它会直接返回该值。
async function foo() {
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("Done!"), 1000);
});
let result = await promise; // 等待,直到promise解决
console.log(result); // 输出 "Done!"
}
foo();
错误处理
使用 try…catch 语句来处理 async 函数中的错误。这使得错误处理更加直观。
async function foo() {
try {
let promise = new Promise((resolve, reject) => {
setTimeout(() => reject("Something went wrong!"), 1000);
});
let result = await promise; // 这里会抛出一个异常
console.log(result); // 不会执行到这里
} catch (error) {
console.error(error); // 输出 "Something went wrong!"
}
}
foo();
示例:获取数据并处理
假设我们有一个函数 fetchData,它返回一个 Promise,模拟从服务器获取数据。
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
let success = true; // 模拟成功或失败
if (success) {
resolve({ data: "Server data" });
} else {
reject("Failed to fetch data");
}
}, 1000);
});
}
使用 async/await 处理异步数据获取和处理:
async function processData() {
try {
let response = await fetchData();
console.log(response.data); // 输出 "Server data"
// 进一步处理数据
let processedData = `Processed: ${response.data}`;
console.log(processedData); // 输出 "Processed: Server data"
return processedData;
} catch (error) {
console.error(error); // 输出错误信息
} finally {
console.log("Fetch operation completed."); // 无论成功或失败都会执行
}
}
processData().then(result => {
console.log(result); // 输出 "Processed: Server data"
});
多个 await 操作
你可以在 async 函数中使用多个 await 来依次等待多个异步操作的完成:
async function multipleAsyncOperations() {
let data1 = await fetchData();
console.log(data1.data); // 输出 "Server data"
let data2 = await anotherAsyncOperation();
console.log(data2.data); // 输出 "Another data"
return [data1, data2];
}
multipleAsyncOperations().then(result => {
console.log(result); // 输出 [data1, data2]
});
并行执行异步操作
如果多个异步操作之间没有依赖关系,可以使用 Promise.all 来并行执行它们,从而提高效率:
async function parallelAsyncOperations() {
let promise1 = fetchData();
let promise2 = anotherAsyncOperation();
let [data1, data2] = await Promise.all([promise1, promise2]);
console.log(data1.data); // 输出 "Server data"
console.log(data2.data); // 输出 "Another data"
}
parallelAsyncOperations();
注意事项
await 只能在 async 函数中使用:在 async 函数之外使用 await 会导致语法错误。
错误处理:使用 try…catch 块来捕获和处理 await 操作中的错误。
避免阻塞:虽然 async/await 使得代码看起来像同步代码,但它仍然是异步的,不会阻塞事件循环。
示例:综合使用
以下是一个综合示例,展示了如何使用 async/await 进行数据获取、处理和错误处理。
// 模拟异步数据获取函数
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
let success = true;
if (success) {
resolve({ data: "Server data" });
} else {
reject("Failed to fetch data");
}
}, 1000);
});
}
// 另一个模拟异步操作函数
function anotherAsyncOperation() {
return new Promise((resolve, reject) => {
setTimeout(() => {
let success = true;
if (success) {
resolve({ data: "Another data" });
} else {
reject("Failed another operation");
}
}, 1000);
});
}
// 综合使用async/await处理多个异步操作
async function processData() {
try {
console.log("Fetching data...");
let data = await fetchData();
console.log("Data received:", data.data);
console.log("Performing another async operation...");
let anotherData = await anotherAsyncOperation();
console.log("Another data received:", anotherData.data);
let combinedData = `${data.data} & ${anotherData.data}`;
console.log("Combined data:", combinedData);
return combinedData;
} catch (error) {
console.error("Error occurred:", error);
} finally {
console.log("Process completed.");
}
}
// 调用综合函数
processData().then(result => {
console.log("Final result:", result);
});
以上内容涵盖了 async/await 的基本用法、错误处理、多 await 操作、并行执行以及注意事项。掌握这些内容有助于更高效地编写和理解异步JavaScript代码。