跳转至

异步编程:Async/Await

概述

在 JavaScript 中,异步编程是处理耗时操作(如网络请求、文件读写等)的关键。ES8(ECMAScript 2017)引入了 async/await 语法,使得异步代码的编写和阅读更加直观和简洁。async/await 是基于 Promise 的语法糖,它允许我们以同步的方式编写异步代码。

基本概念

async 函数

async 函数是使用 async 关键字声明的函数。它总是返回一个 Promise 对象。如果函数返回值不是 Promise,它会被自动包装成一个 resolved 状态的 Promise。

async function myFunction() {
  return "Hello, World!";
}

myFunction().then(alert); // 弹出 "Hello, World!"

await 表达式

await 关键字只能在 async 函数内部使用。它会暂停 async 函数的执行,等待 Promise 完成并返回其结果。如果 Promise 被拒绝,await 会抛出异常。

async function fetchData() {
  let response = await fetch('https://api.example.com/data');
  let data = await response.json();
  return data;
}

代码示例

示例 1: 基本用法

// 定义一个返回 Promise 的函数
function fetchData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve("Data fetched!");
    }, 1000);
  });
}

// 使用 async/await 处理异步操作
async function getData() {
  console.log("Fetching data...");
  let result = await fetchData(); // 等待 Promise 完成
  console.log(result); // 输出 "Data fetched!"
}

getData();

解释: - fetchData 函数模拟了一个异步操作,1秒后返回数据。 - getData 函数使用 await 等待 fetchData 的结果,然后输出。

示例 2: 错误处理

// 定义一个可能失败的 Promise
function fetchData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      reject("Error: Data could not be fetched!");
    }, 1000);
  });
}

// 使用 try/catch 处理错误
async function getData() {
  try {
    console.log("Fetching data...");
    let result = await fetchData(); // 等待 Promise 完成
    console.log(result);
  } catch (error) {
    console.error(error); // 输出 "Error: Data could not be fetched!"
  }
}

getData();

解释: - fetchData 函数模拟了一个失败的异步操作。 - getData 函数使用 try/catch 捕获 await 抛出的异常。

示例 3: 并行执行多个异步操作

// 定义两个返回 Promise 的函数
function fetchUser() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({ name: "John Doe" });
    }, 1000);
  });
}

function fetchPosts() {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(["Post 1", "Post 2"]);
    }, 1500);
  });
}

// 并行执行多个异步操作
async function getUserAndPosts() {
  let [user, posts] = await Promise.all([fetchUser(), fetchPosts()]);
  console.log(user); // 输出 { name: "John Doe" }
  console.log(posts); // 输出 ["Post 1", "Post 2"]
}

getUserAndPosts();

解释: - fetchUserfetchPosts 函数分别模拟了两个异步操作。 - getUserAndPosts 函数使用 Promise.all 并行执行这两个操作,并使用 await 等待它们全部完成。

练习题

练习 1: 基本 async/await 使用

编写一个 async 函数 fetchUserData,它调用一个返回 Promise 的函数 fetchUser,并使用 await 等待结果。fetchUser 函数应该在 1 秒后返回用户数据 { name: "Alice", age: 25 }

练习 2: 错误处理

修改上面的 fetchUserData 函数,使其在 fetchUser 失败时捕获错误并输出 "Failed to fetch user data"。

练习 3: 并行执行

编写一个 async 函数 fetchAllData,它并行调用 fetchUserfetchPosts 函数,并输出用户数据和帖子列表。fetchPosts 函数应该在 1.5 秒后返回帖子列表 ["Post 1", "Post 2"]

总结

  • async/await 是 ES8 引入的语法糖,用于简化异步代码的编写。
  • async 函数总是返回一个 Promise。
  • await 关键字只能在 async 函数内部使用,它会暂停函数的执行,直到 Promise 完成。
  • 使用 try/catch 可以捕获 await 抛出的异常。
  • 使用 Promise.all 可以并行执行多个异步操作。

通过掌握 async/await,你可以编写出更加简洁、易读的异步代码,提高开发效率和代码质量。