MST

星途 面试题库

面试题:JavaScript async/await 实现原理及优化

深入剖析 JavaScript 中 async/await 的内部实现原理,包括它是如何基于 Generator 函数和 Promise 进行工作的。同时,请提出至少两种在大型项目中优化 async/await 使用的策略,并详细解释其原理和优势。
47.4万 热度难度
编程语言JavaScript

知识考点

AI 面试

面试题答案

一键面试

async/await 内部实现原理

  1. 基于 Generator 函数
    • Generator 函数是一种异步函数,它通过 yield 关键字暂停和恢复执行。例如:
    function* gen() {
        yield 1;
        yield 2;
        return 3;
    }
    const g = gen();
    console.log(g.next()); // { value: 1, done: false }
    console.log(g.next()); // { value: 2, done: false }
    console.log(g.next()); // { value: 3, done: true }
    
    • async 函数本质上是 Generator 函数的语法糖,它自动将异步操作包装在 Promise 中。async 函数内部的代码在遇到 await 时,会暂停执行,就如同 yield 暂停 Generator 函数一样。
  2. 基于 Promise
    • await 只能在 async 函数内部使用,它等待一个 Promise 对象解决(resolved)或被拒绝(rejected)。当 await 一个 Promise 时,async 函数的执行会暂停,直到该 Promise 被解决。例如:
    async function asyncFunc() {
        const result = await Promise.resolve(42);
        return result;
    }
    asyncFunc().then(console.log); // 42
    
    • 如果 await 的 Promise 被拒绝,async 函数会抛出错误,这可以通过 try - catch 块捕获。例如:
    async function asyncFunc() {
        try {
            const result = await Promise.reject(new Error('Error!'));
        } catch (error) {
            console.error('Caught error:', error.message);
        }
    }
    asyncFunc();
    
    • async 函数返回一个值时,这个值会被自动包装成已解决的 Promise。如果 async 函数抛出错误,它会被包装成被拒绝的 Promise。

大型项目中优化 async/await 使用的策略

  1. 并行执行多个异步操作
    • 原理:使用 Promise.all 来并行执行多个 async 操作。Promise.all 接受一个 Promise 数组作为参数,它返回一个新的 Promise,只有当所有输入的 Promise 都被解决时,这个新的 Promise 才会被解决;如果有任何一个 Promise 被拒绝,新的 Promise 就会被拒绝。例如:
    async function fetchData1() {
        return new Promise(resolve => setTimeout(() => resolve('Data1'), 1000));
    }
    async function fetchData2() {
        return new Promise(resolve => setTimeout(() => resolve('Data2'), 1500));
    }
    async function main() {
        const [data1, data2] = await Promise.all([fetchData1(), fetchData2()]);
        console.log(data1, data2);
    }
    main();
    
    • 优势:可以显著提高性能,因为多个异步操作不再按顺序执行,而是同时进行。在大型项目中,比如需要从多个 API 端点获取数据时,这种方式能减少整体的等待时间。
  2. 错误处理优化
    • 原理:在 async 函数中统一使用 try - catch 块来处理错误,避免多个 await 导致的重复错误处理代码。同时,可以封装一个错误处理函数,将错误处理逻辑集中起来。例如:
    function handleError(error) {
        console.error('Global error handler:', error.message);
    }
    async function asyncFunc() {
        try {
            const result1 = await Promise.reject(new Error('Error in result1'));
            const result2 = await Promise.resolve('Result2');
        } catch (error) {
            handleError(error);
        }
    }
    asyncFunc();
    
    • 优势:提高代码的可维护性和可读性,在大型项目中,集中的错误处理使得错误追踪和修复更加容易,避免了在每个 await 处都重复编写类似的错误处理代码。