MST

星途 面试题库

面试题:Node.js异步编程之async/await深度剖析

假设你正在开发一个复杂的Node.js应用,其中有多个异步操作相互交织,部分操作需要并发执行,部分需要顺序执行。请使用async/await语法实现该场景,并详细说明如何通过try - catch块处理异常,以及在这种复杂异步场景下,async/await相较于Promise的优势和潜在问题。
12.7万 热度难度
前端开发Node.js

知识考点

AI 面试

面试题答案

一键面试

使用async/await实现复杂异步场景

假设我们有三个异步操作 asyncOperation1asyncOperation2asyncOperation3,其中 asyncOperation1asyncOperation2 并发执行,然后 asyncOperation3 在它们完成后顺序执行。

function asyncOperation1() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('Operation 1 completed');
        }, 1000);
    });
}

function asyncOperation2() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('Operation 2 completed');
        }, 1500);
    });
}

function asyncOperation3() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('Operation 3 completed');
        }, 1200);
    });
}

async function main() {
    try {
        const [result1, result2] = await Promise.all([asyncOperation1(), asyncOperation2()]);
        console.log(result1);
        console.log(result2);

        const result3 = await asyncOperation3();
        console.log(result3);
    } catch (error) {
        console.error('An error occurred:', error);
    }
}

main();

通过try - catch块处理异常

在上述代码中,try - catch 块包裹了所有的异步操作。Promise.all 用于并发执行 asyncOperation1asyncOperation2。如果任何一个Promise被拒绝,Promise.all 会立即拒绝,并抛出错误,这个错误会被 catch 块捕获。await 操作符后的Promise如果被拒绝,同样会抛出错误,也会被 catch 块捕获。这样就可以在一个地方统一处理所有异步操作中可能出现的错误。

async/await相较于Promise的优势

  1. 代码更简洁易读async/await 基于 Promise 构建,但语法上更接近同步代码,使得异步代码看起来和同步代码类似,大大提高了代码的可读性。例如上述代码,await 使得我们可以按顺序书写异步操作,而不需要像链式调用 Promise 那样层层嵌套。
  2. 错误处理更直观:通过 try - catch 块可以统一捕获所有异步操作中的错误,而在 Promise 链式调用中,需要在每个 catch 块分别处理错误,或者在最后统一处理,相对复杂。

async/await潜在问题

  1. 阻塞问题await 会阻塞其所在函数中后续代码的执行,直到Promise被解决。如果在一个循环中使用 await,可能会导致性能问题,因为每次迭代都要等待前一个异步操作完成。在这种情况下,可能需要结合 Promise.all 等方法并发执行部分异步操作。
  2. 难以调试:由于 async/await 语法糖的存在,错误堆栈可能不够清晰。当发生错误时,调试工具可能无法直接定位到实际出错的异步操作位置,需要花费更多精力去排查。