MST

星途 面试题库

面试题:网络编程:深入探讨 Promise 与 async/await 在 Node.js 网络编程异常处理与可靠性保障

在复杂的 Node.js 后端网络编程项目中,涉及到多层异步嵌套和多个异步任务的协同工作,使用 Promise 和 async/await 处理异步操作。请详细分析如何构建一个全面且健壮的异常处理机制,确保即使部分异步操作失败,整个系统仍能保持稳定运行,并且能有效记录错误信息以便调试。同时,说明如何通过 Promise 和 async/await 提升网络服务的可靠性,如应对网络波动、超时等情况。
32.1万 热度难度
后端开发网络编程

知识考点

AI 面试

面试题答案

一键面试

异常处理机制

  1. try - catch 块
    • async 函数内部使用 try - catch 块来捕获异步操作中抛出的错误。例如:
    async function asyncTask() {
        try {
            let result1 = await someAsyncFunction1();
            let result2 = await someAsyncFunction2(result1);
            // 更多异步操作
        } catch (error) {
            // 记录错误信息
            console.error('捕获到错误:', error);
            // 可以在这里进行一些恢复操作,比如返回默认值
            return defaultResult;
        }
    }
    
    • 这样可以捕获 someAsyncFunction1someAsyncFunction2 执行过程中抛出的错误,确保错误不会导致整个系统崩溃。
  2. Promise.catch
    • 对于不使用 async/awaitPromise 链式调用,可以在链的末尾使用 .catch 方法捕获错误。例如:
    someAsyncFunction1()
       .then(result1 => someAsyncFunction2(result1))
       .then(result2 => {
            // 处理结果
        })
       .catch(error => {
            console.error('捕获到错误:', error);
            // 进行错误处理
        });
    
  3. 全局异常处理
    • 在 Node.js 应用中,可以使用 process.on('uncaughtException') 来捕获未被 try - catch.catch 处理的异常。
    process.on('uncaughtException', (error) => {
        console.error('全局捕获到未处理异常:', error);
        // 可以进行紧急日志记录,甚至优雅停机等操作
    });
    
    • 同时,对于未被处理的 Promise 拒绝,可以使用 process.on('unhandledRejection')
    process.on('unhandledRejection', (reason, promise) => {
        console.error('全局捕获到未处理的 Promise 拒绝:', reason, 'Promise:', promise);
    });
    
  4. 错误记录
    • 使用日志库(如 winstonpino)来记录错误信息。这些库可以将错误信息记录到文件、控制台等不同的目标,方便调试。例如,使用 winston
    const winston = require('winston');
    
    const logger = winston.createLogger({
        level: 'error',
        format: winston.format.json(),
        transports: [
            new winston.transport.Console(),
            new winston.transport.File({ filename: 'error.log' })
        ]
    });
    
    async function asyncTask() {
        try {
            // 异步操作
        } catch (error) {
            logger.error('发生错误:', error.message, { stack: error.stack });
            return defaultResult;
        }
    }
    

提升网络服务可靠性

  1. 应对网络波动
    • 重试机制:在网络请求失败时,使用 Promise 实现重试逻辑。例如:
    async function retryAsyncFunction(func, maxRetries = 3, delay = 1000) {
        let retries = 0;
        while (retries < maxRetries) {
            try {
                return await func();
            } catch (error) {
                retries++;
                if (retries === maxRetries) {
                    throw error;
                }
                await new Promise(resolve => setTimeout(resolve, delay));
            }
        }
    }
    
    async function networkRequest() {
        // 网络请求函数
        return new Promise((resolve, reject) => {
            // 模拟网络请求
            setTimeout(() => {
                Math.random() > 0.5? resolve('成功') : reject('失败');
            }, 1000);
        });
    }
    
    retryAsyncFunction(networkRequest).then(result => {
        console.log('最终结果:', result);
    }).catch(error => {
        console.error('经过重试仍失败:', error);
    });
    
  2. 超时处理
    • 使用 Promise.race 来实现超时机制。例如:
    async function timeoutAsyncFunction(func, timeout = 5000) {
        return Promise.race([
            func(),
            new Promise((_, reject) => {
                setTimeout(() => {
                    reject(new Error('操作超时'));
                }, timeout);
            })
        ]);
    }
    
    async function longRunningNetworkRequest() {
        return new Promise((resolve) => {
            setTimeout(() => {
                resolve('成功');
            }, 8000);
        });
    }
    
    timeoutAsyncFunction(longRunningNetworkRequest, 5000).then(result => {
        console.log('结果:', result);
    }).catch(error => {
        console.log('错误:', error.message);
    });
    

通过上述方法,使用 Promiseasync/await 能够构建全面且健壮的异常处理机制,并提升网络服务在复杂情况下的可靠性。