JavaScript async/await

小飞兽 HTML/CSS 1 次阅读 2026-08-13

JavaScript async/await

在讲解 async/await 之前,我们需要先理解 JavaScript 中的异步编程概念,可以参考:JavaScript 异步编程

JavaScript 是单线程语言,意味着它一次只能执行一个任务。为了避免长时间运行的任务阻塞主线程,JavaScript 使用异步编程模型。

异步 vs 同步

    • 同步(Synchronous)编程:代码按顺序执行,前一个操作完成后才会执行下一个
    • 异步编程(Asynchronous):某些操作被放入"任务队列",主线程继续执行后续代码,等主线程空闲时再处理队列中的任务

    实例

    // 同步示例
    console.log('1');
    console.log('2');
    // 输出: 1, 2

    // 异步示例
    console.log('1');
    setTimeout(() => console.log('2'), 0);
    console.log('3');
    // 输出: 1, 3, 2

    回调函数的问题

    在 async/await 出现之前,JavaScript 主要使用回调函数处理异步操作,但这会导致"回调地狱"(Callback Hell)。

    实例

    getData(function(a) {
      getMoreData(a, function(b) {
        getMoreData(b, function(c) {
          getMoreData(c, function(d) {
            console.log(d);
          });
        });
      });
    });

    这种嵌套结构使得代码难以阅读和维护。


    Promise 的引入

    ES6 引入了 Promise 对象来解决回调地狱问题。

    实例

    function getData() {
      return new Promise((resolve, reject) => {
        // 异步操作
        setTimeout(() => resolve('数据'), 1000);
      });
    }

    getData()
      .then(data => {
        console.log(data);
        return getMoreData(data);
      })
      .then(moreData => {
        console.log(moreData);
      })
      .catch(error => {
        console.error(error);
      });

    虽然 Promise 改善了回调问题,但 then() 链式调用仍然不够直观。


    async/await 语法

    ES2017 引入了 async/await,它建立在 Promise 之上,让异步代码看起来像同步代码一样。

    async 函数

    在函数声明前添加 async 关键字,表示该函数是异步的:

    async function fetchData() {
      // 函数体
    }

    async 函数总是返回一个 Promise:

    • 如果返回值不是 Promise,会自动包装成 resolved Promise
    • 如果抛出异常,会返回 rejected Promise

    await 表达式

    await 只能在 async 函数内部使用:

    async function fetchData() {
      const result = await somePromise;
      console.log(result);
    }

    await 会暂停 async 函数的执行,等待 Promise 完成:

    • 如果 Promise 被 resolve,返回 resolve 的值
    • 如果 Promise 被 reject,抛出错误(可以用 try/catch 捕获)

    实际应用示例

    基本用法

    实例

    function delay(ms) {
      return new Promise(resolve => setTimeout(resolve, ms));
    }

    async function showMessage() {
      console.log('开始');
      await delay(1000);
      console.log('1秒后');
      await delay(1000);
      console.log('又1秒后');
    }

    showMessage();

    错误处理

    实例

    async function fetchUserData() {
      try {
        const response = await fetch('https://api.example.com/user');
        if (!response.ok) {
          throw new Error('网络响应不正常');
        }
        const data = await response.json();
        console.log(data);
      } catch (error) {
        console.error('获取数据失败:', error);
      }
    }

    并行执行

    如果需要并行执行多个异步操作,可以使用 Promise.all:

    实例

    async function fetchMultipleData() {
      const [userData, productData] = await Promise.all([
        fetch('/api/user'),
        fetch('/api/products')
      ]);
     
      const user = await userData.json();
      const products = await productData.json();
     
      return { user, products };
    }

    常见问题与最佳实践

    1. 不要忘记 await

    实例

    // 错误示例 - 忘记 await
    async function example() {
      const data = fetch('/api'); // 缺少 await
      console.log(data); // 输出 Promise 对象
    }

    // 正确示例
    async function example() {
      const data = await fetch('/api');
      console.log(data); // 输出实际数据
    }

    2. 避免不必要的 async

    实例

    // 不必要 - 函数内部没有 await
    async function unnecessaryAsync() {
      return 42;
    }

    // 更简单的写法
    function simpleFunction() {
      return 42;
    }

    3. 顶层 await

    在模块顶层可以直接使用 await(ES2022 特性):

    实例

    // 在模块中
    const data = await fetch('/api');
    console.log(data);

    4. 性能考虑

    • 顺序执行 vs 并行执行:合理使用 Promise.all 提高性能
    • 错误处理:确保所有可能的错误都被捕获

    async/await 与传统 Promise 对比

    特性 async/await Promise then/catch
    可读性 高,类似同步代码 中,链式调用
    错误处理 使用 try/catch 使用 .catch()
    调试 更容易,有明确的调用栈 较困难,调用栈可能不清晰
    代码结构 更扁平 嵌套或链式

    总结

    async/await 是 JavaScript 异步编程的重大改进,它:

    1. 使异步代码更易读、更易维护
  • 基于 Promise,与现有 Promise 代码兼容
  • 提供了更直观的错误处理方式
  • 改善了调试体验

虽然 async/await 不是完全替代 Promise,但在大多数情况下,它提供了更优雅的解决方案。理解 async/await 的工作原理和最佳实践,将大大提升你的 JavaScript 异步编程能力。