MST

星途 面试题库

面试题:JavaScript 中 async 和 await 的基本性能优势及使用场景

请简要阐述 JavaScript 中 async 和 await 相较于传统回调函数与 Promise 在性能方面的优势,并举例说明其适用的应用场景。
12.8万 热度难度
编程语言JavaScript

知识考点

AI 面试

面试题答案

一键面试

性能优势

  1. 代码可读性与维护性提升
    • 传统回调函数:会出现回调地狱问题,例如多层嵌套的setTimeout回调:
    setTimeout(() => {
        setTimeout(() => {
            setTimeout(() => {
                console.log('回调地狱');
            }, 1000);
        }, 1000);
    }, 1000);
    
    这样的代码逻辑复杂,难以阅读和维护。
    • Promise:通过链式调用解决了回调地狱问题,例如:
    new Promise((resolve) => {
        setTimeout(() => {
            resolve();
        }, 1000);
    })
    

.then(() => { return new Promise((resolve) => { setTimeout(() => { resolve(); }, 1000); }); }) .then(() => { console.log('Promise 链式调用'); });

但链式调用依然不够简洁。
- **async/await**:以同步风格编写异步代码,例如:
```javascript
async function asyncFunc() {
    await new Promise((resolve) => {
        setTimeout(() => {
            resolve();
        }, 1000);
    });
    await new Promise((resolve) => {
        setTimeout(() => {
            resolve();
        }, 1000);
    });
    console.log('async/await 同步风格');
}
asyncFunc();

代码结构更清晰,减少人为错误,从间接提升性能(因代码易读易维护,可减少调试和优化时间)。 2. 错误处理简化

  • 传统回调函数:错误处理需要在每个回调函数中单独进行,例如:
function asyncTask(callback) {
    setTimeout(() => {
        const error = true;
        if (error) {
            callback(new Error('出错了'));
        } else {
            callback(null, '成功');
        }
    }, 1000);
}
asyncTask((err, result) => {
    if (err) {
        console.error(err);
    } else {
        console.log(result);
    }
});

多个异步操作时,错误处理代码重复且繁琐。

  • Promise:通过.catch统一处理错误,例如:
new Promise((resolve, reject) => {
    setTimeout(() => {
        const error = true;
        if (error) {
            reject(new Error('出错了'));
        } else {
            resolve('成功');
        }
    }, 1000);
})
.then((result) => {
    console.log(result);
})
.catch((err) => {
    console.error(err);
});
  • async/await:使用try...catch块处理错误,更接近同步代码的错误处理方式,例如:
async function asyncTask() {
    try {
        await new Promise((resolve, reject) => {
            setTimeout(() => {
                const error = true;
                if (error) {
                    reject(new Error('出错了'));
                } else {
                    resolve('成功');
                }
            }, 1000);
        });
    } catch (err) {
        console.error(err);
    }
}
asyncTask();

简化的错误处理使代码更简洁,减少错误处理逻辑带来的性能开销(如重复代码执行等)。

适用场景

  1. 顺序执行异步操作
    • 例如在用户注册流程中,先检查用户名是否存在,再创建用户,最后发送欢迎邮件。
    async function registerUser(username, password) {
        try {
            // 检查用户名是否存在
            const exists = await checkUsernameExists(username);
            if (exists) {
                throw new Error('用户名已存在');
            }
            // 创建用户
            const user = await createUser(username, password);
            // 发送欢迎邮件
            await sendWelcomeEmail(user.email);
            console.log('用户注册成功');
        } catch (err) {
            console.error(err);
        }
    }
    async function checkUsernameExists(username) {
        return new Promise((resolve) => {
            setTimeout(() => {
                resolve(false);
            }, 1000);
        });
    }
    async function createUser(username, password) {
        return new Promise((resolve) => {
            setTimeout(() => {
                resolve({ username, password, email: 'user@example.com' });
            }, 1000);
        });
    }
    async function sendWelcomeEmail(email) {
        return new Promise((resolve) => {
            setTimeout(() => {
                console.log(`已向 ${email} 发送欢迎邮件`);
                resolve();
            }, 1000);
        });
    }
    registerUser('testuser', 'testpassword');
    
  2. 处理多个异步操作结果后进行下一步
    • 例如在获取多个 API 数据后进行合并处理。假设要从两个 API 获取用户信息和订单信息,然后合并展示。
    async function getUserAndOrderInfo() {
        try {
            const userPromise = getUserInfo();
            const orderPromise = getOrderInfo();
            const [user, order] = await Promise.all([userPromise, orderPromise]);
            const combinedInfo = { user, order };
            console.log(combinedInfo);
        } catch (err) {
            console.error(err);
        }
    }
    async function getUserInfo() {
        return new Promise((resolve) => {
            setTimeout(() => {
                resolve({ name: 'John', age: 30 });
            }, 1000);
        });
    }
    async function getOrderInfo() {
        return new Promise((resolve) => {
            setTimeout(() => {
                resolve({ orderId: 123, amount: 100 });
            }, 1000);
        });
    }
    getUserAndOrderInfo();
    
    在这个场景中,async/await结合Promise.all能清晰地处理多个异步操作,并在所有操作完成后进行统一处理。