MST

星途 面试题库

面试题:JavaScript 异步编程 - Async/Await 与 Promise 的深入比较

Async/Await 是基于 Promise 实现的语法糖,请详细说明 Async/Await 相对于 Promise 在异步操作方面的优势与劣势,并且举例说明在处理复杂异步流程控制(如并发与顺序执行混合场景)时,如何更好地使用它们。
10.6万 热度难度
编程语言JavaScript

知识考点

AI 面试

面试题答案

一键面试

优势

  1. 代码更简洁易读
    • Promise 链式调用时,多层 then 嵌套会使代码可读性变差,形成 “回调地狱”。而 Async/Await 以同步代码的形式书写异步逻辑,更符合人类思维习惯。
    • 示例
      // Promise 写法
      function fetchData1() {
        return new Promise((resolve) => {
          setTimeout(() => {
            resolve('Data1');
          }, 1000);
        });
      }
      function fetchData2(data1) {
        return new Promise((resolve) => {
          setTimeout(() => {
            resolve(data1 + ' and Data2');
          }, 1000);
        });
      }
      fetchData1()
       .then(data1 => fetchData2(data1))
       .then(finalData => console.log(finalData));
      // Async/Await 写法
      async function getData() {
        const data1 = await fetchData1();
        const finalData = await fetchData2(data1);
        console.log(finalData);
      }
      getData();
      
  2. 错误处理更优雅
    • Promise 中错误处理通过 .catch 统一捕获,在多层嵌套时难以精准定位错误。Async/Await 可以使用 try - catch 块,与同步代码错误处理方式一致,更直观。
    • 示例
      // Promise 错误处理
      function errorPromise() {
        return new Promise((_, reject) => {
          setTimeout(() => {
            reject(new Error('Promise error'));
          }, 1000);
        });
      }
      errorPromise()
       .catch(error => console.error('Promise catch:', error.message));
      // Async/Await 错误处理
      async function asyncError() {
        try {
          await errorPromise();
        } catch (error) {
          console.error('Async/Await catch:', error.message);
        }
      }
      asyncError();
      
  3. 条件语句和循环中使用更方便
    • 在 Promise 中,在条件语句或循环内部处理异步操作较繁琐。Async/Await 可以像同步代码一样在条件和循环中使用。
    • 示例
      // Promise 在循环中的使用
      const promises = [];
      for (let i = 0; i < 5; i++) {
        promises.push(new Promise((resolve) => {
          setTimeout(() => {
            resolve(i);
          }, 1000 * i);
        }));
      }
      Promise.all(promises).then(results => console.log(results));
      // Async/Await 在循环中的使用
      async function loopAsync() {
        for (let i = 0; i < 5; i++) {
          const result = await new Promise((resolve) => {
            setTimeout(() => {
              resolve(i);
            }, 1000 * i);
          });
          console.log(result);
        }
      }
      loopAsync();
      

劣势

  1. 缺乏内置的并发控制
    • Promise 有 Promise.allPromise.race 等方法可方便地控制并发。Async/Await 本身没有这样的内置方法直接处理并发,需要借助外部工具或自己封装。
    • 示例
      // Promise 并发处理
      const promise1 = new Promise((resolve) => {
        setTimeout(() => {
          resolve('Promise1');
        }, 2000);
      });
      const promise2 = new Promise((resolve) => {
        setTimeout(() => {
          resolve('Promise2');
        }, 1000);
      });
      Promise.all([promise1, promise2]).then(results => console.log(results));
      // Async/Await 并发处理需手动封装
      async function asyncConcurrent() {
        const promise1 = new Promise((resolve) => {
          setTimeout(() => {
            resolve('Promise1');
          }, 2000);
        });
        const promise2 = new Promise((resolve) => {
          setTimeout(() => {
            resolve('Promise2');
          }, 1000);
        });
        const results = await Promise.all([promise1, promise2]);
        console.log(results);
      }
      asyncConcurrent();
      
  2. 错误处理的全局性
    • 在 Async/Await 中,如果一个异步函数内部未捕获错误,整个函数会抛出错误,需要在外部统一捕获。相比之下,Promise 可以在每个 then 链中独立处理错误。

复杂异步流程控制(并发与顺序执行混合场景)

  1. 并发执行部分任务,再顺序执行
    • Promise 示例
      function task1() {
        return new Promise((resolve) => {
          setTimeout(() => {
            resolve('Task1');
          }, 1000);
        });
      }
      function task2() {
        return new Promise((resolve) => {
          setTimeout(() => {
            resolve('Task2');
          }, 1500);
        });
      }
      function task3(result1, result2) {
        return new Promise((resolve) => {
          setTimeout(() => {
            resolve(result1 + ' and ' + result2 + ' and Task3');
          }, 1000);
        });
      }
      Promise.all([task1(), task2()])
       .then(([result1, result2]) => task3(result1, result2))
       .then(finalResult => console.log(finalResult));
      
    • Async/Await 示例
      async function asyncTask() {
        const [result1, result2] = await Promise.all([task1(), task2()]);
        const finalResult = await task3(result1, result2);
        console.log(finalResult);
      }
      asyncTask();
      
  2. 顺序执行部分任务,再并发执行
    • Promise 示例
      function step1() {
        return new Promise((resolve) => {
          setTimeout(() => {
            resolve('Step1');
          }, 1000);
        });
      }
      function step2(result1) {
        return new Promise((resolve) => {
          setTimeout(() => {
            resolve(result1 + ' and Step2');
          }, 1000);
        });
      }
      function concurrentTask1(result2) {
        return new Promise((resolve) => {
          setTimeout(() => {
            resolve(result2 + ' and Concurrent1');
          }, 1500);
        });
      }
      function concurrentTask2(result2) {
        return new Promise((resolve) => {
          setTimeout(() => {
            resolve(result2 + ' and Concurrent2');
          }, 1200);
        });
      }
      step1()
       .then(result1 => step2(result1))
       .then(result2 => Promise.all([concurrentTask1(result2), concurrentTask2(result2)]))
       .then(finalResults => console.log(finalResults));
      
    • Async/Await 示例
      async function asyncMixed() {
        const result1 = await step1();
        const result2 = await step2(result1);
        const finalResults = await Promise.all([concurrentTask1(result2), concurrentTask2(result2)]);
        console.log(finalResults);
      }
      asyncMixed();