MST

星途 面试题库

面试题:JavaScript回调函数与其他异步模式的深度对比及应用场景

在JavaScript异步编程中,回调函数、Promise、async/await各有特点。请详细阐述回调函数与Promise、async/await在处理异步任务方面的异同点,并结合实际项目场景,说明在哪些情况下应该优先选择回调函数,哪些情况下更适合使用Promise或async/await ,给出相应的示例代码。
46.9万 热度难度
编程语言JavaScript

知识考点

AI 面试

面试题答案

一键面试

异同点

  1. 相同点:都用于处理JavaScript中的异步任务,解决异步操作导致的代码执行顺序问题。
  2. 不同点
    • 回调函数:通过将一个函数作为参数传递给另一个异步执行的函数,在异步操作完成时调用。它容易导致回调地狱,代码可读性和维护性差。例如:
fs.readFile('file.txt', 'utf8', function(err, data) {
    if (err) {
        console.error(err);
        return;
    }
    console.log(data);
});
- **Promise**:是一个代表异步操作最终完成(或失败)及其结果的对象。它通过链式调用解决了回调地狱问题,代码更易读。例如:
const fs = require('fs').promises;
fs.readFile('file.txt', 'utf8')
   .then(data => {
        console.log(data);
    })
   .catch(err => {
        console.error(err);
    });
- **async/await**:是基于Promise的语法糖,以同步风格编写异步代码,看起来更简洁直观。例如:
const fs = require('fs').promises;
async function readFileAsync() {
    try {
        const data = await fs.readFile('file.txt', 'utf8');
        console.log(data);
    } catch (err) {
        console.error(err);
    }
}
readFileAsync();

适用场景

  1. 回调函数
    • 场景:在简单的、一次性的异步操作中,并且代码逻辑不复杂时可以使用。例如在一些简单的事件监听回调场景。
    • 示例
document.addEventListener('click', function() {
    console.log('Clicked!');
});
  1. Promise
    • 场景:当需要处理多个异步操作,并且这些操作存在链式依赖关系时,Promise的链式调用能很好地组织代码。例如,在一个需要依次进行多个API调用的场景中。
    • 示例
function apiCall1() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('Result of apiCall1');
        }, 1000);
    });
}
function apiCall2(result1) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(result1 +'and result of apiCall2');
        }, 1000);
    });
}
apiCall1()
   .then(result1 => apiCall2(result1))
   .then(finalResult => console.log(finalResult));
  1. async/await
    • 场景:当异步操作逻辑复杂,需要大量的异步操作组合,并且希望代码尽可能以同步的方式书写和阅读时,async/await是最佳选择。例如,在处理复杂的数据库事务时。
    • 示例
const mysql = require('mysql2/promise');
async function transaction() {
    const connection = await mysql.createConnection({
        host: 'localhost',
        user: 'root',
        password: 'password',
        database: 'test'
    });
    try {
        await connection.beginTransaction();
        await connection.execute('UPDATE users SET balance = balance - 100 WHERE id = 1');
        await connection.execute('UPDATE users SET balance = balance + 100 WHERE id = 2');
        await connection.commit();
        console.log('Transaction completed successfully');
    } catch (err) {
        await connection.rollback();
        console.error('Transaction failed', err);
    } finally {
        connection.end();
    }
}
transaction();