MST

星途 面试题库

面试题:JavaScript函数定义在异步场景下的适配与优化

在处理复杂异步任务时,使用ES6的async/await定义函数与传统的回调函数和Promise链式调用相比,有哪些优势和需要注意的地方?假设你有一个需要依次调用三个异步API的场景,用async/await定义函数来实现,并解释代码执行流程。
34.4万 热度难度
编程语言JavaScript

知识考点

AI 面试

面试题答案

一键面试

优势

  1. 代码更简洁直观:async/await 以同步代码的风格编写异步代码,相比于层层嵌套的回调函数(回调地狱)和冗长的 Promise 链式调用,逻辑更清晰,更易于理解和维护。例如,处理多个异步操作时,async/await 代码看起来就像普通的顺序执行代码,而不是像 Promise 链式调用那样不断地.then()。
  2. 错误处理更优雅:在 async 函数内部,可以使用 try...catch 块来捕获整个函数内异步操作抛出的错误,而不需要像 Promise 链式调用那样在每个.then() 后面都添加.catch() 来捕获错误。这使得错误处理代码更集中,减少重复代码。
  3. 条件控制更方便:在 async 函数中,可以像普通同步函数一样使用条件语句(如 if...else)来控制异步操作的流程,而在回调函数和 Promise 链式调用中,条件控制可能会变得复杂,尤其是涉及多个异步操作的条件判断时。

需要注意的地方

  1. 必须在 async 函数内部使用:await 关键字只能在 async 函数内部使用,如果在普通函数中使用会导致语法错误。
  2. 错误处理:虽然 try...catch 捕获错误更方便,但如果在 async 函数外部调用该函数,仍然需要通过.catch() 来捕获可能抛出的错误,否则错误可能会被忽略。
  3. 性能:async/await 本质上还是基于 Promise 的,在性能方面并没有比 Promise 链式调用有本质提升。过多的 await 可能会导致代码阻塞,尤其是在一些高并发场景下,需要合理使用以避免性能问题。

示例代码及执行流程

// 模拟异步 API
function asyncAPI1() {
    return new Promise((resolve) => {
        setTimeout(() => {
            console.log('API1 执行完毕');
            resolve('API1 结果');
        }, 1000);
    });
}

function asyncAPI2() {
    return new Promise((resolve) => {
        setTimeout(() => {
            console.log('API2 执行完毕');
            resolve('API2 结果');
        }, 1000);
    });
}

function asyncAPI3() {
    return new Promise((resolve) => {
        setTimeout(() => {
            console.log('API3 执行完毕');
            resolve('API3 结果');
        }, 1000);
    });
}

async function main() {
    try {
        const result1 = await asyncAPI1();
        console.log('result1:', result1);
        const result2 = await asyncAPI2();
        console.log('result2:', result2);
        const result3 = await asyncAPI3();
        console.log('result3:', result3);
    } catch (error) {
        console.error('发生错误:', error);
    }
}

main();

执行流程

  1. 调用 main 函数,函数开始执行。
  2. 遇到 await asyncAPI1()asyncAPI1 开始执行(这里通过 setTimeout 模拟异步操作),main 函数暂停执行,直到 asyncAPI1 的 Promise 被 resolved。
  3. asyncAPI1 执行完毕(1 秒后),await 表达式返回 asyncAPI1 的 resolved 值,赋值给 result1,并继续执行下一行代码,打印 result1: 以及 asyncAPI1 的结果。
  4. 遇到 await asyncAPI2()asyncAPI2 开始执行,main 函数再次暂停,直到 asyncAPI2 的 Promise 被 resolved。
  5. asyncAPI2 执行完毕(1 秒后),await 表达式返回 asyncAPI2 的 resolved 值,赋值给 result2,并继续执行下一行代码,打印 result2: 以及 asyncAPI2 的结果。
  6. 遇到 await asyncAPI3()asyncAPI3 开始执行,main 函数又一次暂停,直到 asyncAPI3 的 Promise 被 resolved。
  7. asyncAPI3 执行完毕(1 秒后),await 表达式返回 asyncAPI3 的 resolved 值,赋值给 result3,并继续执行下一行代码,打印 result3: 以及 asyncAPI3 的结果。
  8. 如果在任何一个 await 操作中抛出错误,代码会跳转到 catch 块,打印错误信息。