代码改变世界

Node.js面试题及详细答案120题(93-100) -- 错误处理与调试篇 - 教程

2025-10-02 21:01  tlnshuju  阅读(35)  评论(0)    收藏  举报

前后端面试题》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,MySQL,Linux… 。

前后端面试题-专栏总目录

在这里插入图片描述

一、本文面试题目录

93. Node.js中的错误类型有哪些?如何捕获全局错误?

Node.js 中的错误可分为多种类型,不同类型对应不同的场景,捕获全局错误能避免程序意外崩溃。

常见错误类型
  1. Error:所有错误的基类,包含错误消息(message)和堆栈跟踪(stack)。
  2. SyntaxError:语法错误(如代码拼写错误),通常在程序启动时抛出。
    // 示例:缺少括号导致语法错误
    function test() { console.log('test') // 缺少 }
  3. TypeError:类型错误(如调用非函数对象)。
    const num = 123;
    num(); // TypeError: num is not a function
  4. ReferenceError:引用错误(如使用未定义的变量)。
    console.log(undefinedVar); // ReferenceError: undefinedVar is not defined
  5. RangeError:范围错误(如数组长度为负数)。
    const arr = new Array(-1); // RangeError: Invalid array length
  6. 自定义错误:通过继承 Error 实现特定业务错误。
    class ValidationError extends Error {
    constructor(message) {
    super(message);
    this.name = 'ValidationError';
    }
    }
捕获全局错误

全局错误指未被局部 try/catch 捕获的错误,需通过事件监听处理:

// 1. 捕获未捕获的同步异常
process.on('uncaughtException', (err) => {
console.error('未捕获的同步异常:', err);
// 必要时进行资源清理后退出进程
process.exit(1);
});
// 2. 捕获未处理的Promise拒绝
process.on('unhandledRejection', (reason, promise) => {
console.error('未处理的Promise拒绝:', reason);
// 可在此处记录日志或进行补救
});
// 3. 捕获警告(非致命错误)
process.on('warning', (warning) => {
console.warn('警告:', warning.message);
});

注意uncaughtException 发生后,进程可能处于不稳定状态,建议记录日志后重启进程。

94. 如何使用try/catch处理异步错误?它能捕获哪些错误?

try/catch 是 JavaScript 处理异常的标准方式,在 Node.js 中可结合 async/await 处理异步错误,但需注意其适用范围。

处理异步错误的方式
  1. async/await + try/catch(推荐):

    const fs = require('fs/promises');
    async function readFile() {
    try {
    // 异步操作:读取文件
    const data = await fs.readFile('nonexistent.txt', 'utf8');
    console.log(data);
    } catch (err) {
    // 捕获异步操作中的错误(如文件不存在)
    console.error('读取失败:', err.message);
    }
    }
    readFile();
  2. Promise链式调用 + catch()

    fs.readFile('nonexistent.txt', 'utf8')
    .then(data => console.log(data))
    .catch(err => console.error('读取失败:', err.message));
try/catch 能捕获的错误
  • 同步错误:如 TypeErrorReferenceError 等。

  • await 后的异步错误:通过 async/await 包装的 Promise 拒绝。

  • 异步回调中的错误(不能直接捕获):需在回调内部处理。

    // 错误示例:try/catch 无法捕获回调中的异步错误
    try {
    fs.readFile('file.txt', (err, data) => {
    if (err) throw err; // 此处错误不会被外部 try/catch 捕获
    });
    } catch (err) {
    console.error('无法捕获此处错误');
    }
    // 正确处理:在回调内部捕获
    fs.readFile('file.txt', (err, data) => {
    try {
    if (err) throw err;
    console.log(data);
    } catch (err) {
    console.error('处理错误:', err);
    }
    });

95. 什么是未捕获异常(Uncaught Exception)?如何处理?

未捕获异常(Uncaught Exception) 指同步代码中抛出的错误未被 try/catch 捕获,导致错误冒泡到事件循环顶层,可能导致程序崩溃。

示例:未捕获异常
// 同步代码抛出错误但未捕获
function throwError() {
throw new Error('致命错误');
}
throwError(); // 未被捕获,触发 uncaughtException 事件
console.log('此处不会执行');
处理方式

通过监听 process 对象的 uncaughtException 事件捕获:

// 注册全局未捕获异常处理器
process.on('uncaughtException', (err) => {
// 1. 记录详细错误日志(包含堆栈)
console.error('未捕获异常:', err.stack);
// 2. 清理资源(如关闭数据库连接、释放文件句柄)
const cleanup = async () => {
try {
await db.disconnect(); // 假设 db 是数据库连接对象
console.log('资源清理完成');
} catch (cleanupErr) {
console.error('清理失败:', cleanupErr);
}
};
// 3. 清理后退出进程(避免不稳定状态)
cleanup().then(() => {
process.exit(1); // 非0退出码表示异常终止
});
});

最佳实践

  • 仅用 uncaughtException 作为最后的安全网,优先通过 try/catch 局部处理。
  • 发生未捕获异常后,进程状态可能不可靠,应重启进程(可配合进程管理工具如 PM2 自动重启)。

96. 什么是未处理的Promise拒绝(Unhandled Rejection)?如何处理?

未处理的Promise拒绝(Unhandled Rejection) 指Promise被拒绝(reject)后,未通过 catch()try/catch 处理,导致错误未被捕获。

示例:未处理的Promise拒绝
// 情况1:Promise链式调用未加 catch()
Promise.reject(new Error('操作失败'))
.then(() => console.log('成功')); // 未处理拒绝
// 情况2:async/await 未用 try/catch
async function test() {
await Promise.reject(new Error('异步失败')); // 未捕获
}
test();
处理方式
  1. 局部处理:为每个Promise添加 catch() 或用 try/catch

    // 方式1:使用 catch()
    Promise.reject(new Error('失败'))
    .catch(err => console.error('处理拒绝:', err));
    // 方式2:使用 try/catch
    async function safeTest() {
    try {
    await Promise.reject(new Error('失败'));
    } catch (err) {
    console.error('处理拒绝:', err);
    }
    }
    safeTest();
  2. 全局处理:监听 unhandledRejection 事件(作为兜底)。

    process.on('unhandledRejection', (reason, promise) => {
    console.error('未处理的Promise拒绝:', reason);
    // 可选:给未处理的Promise添加catch(避免多次触发)
    promise.catch(err => console.error('补捕获:', err));
    });

注意:Node.js 15+ 中,未处理的Promise拒绝会导致进程退出(类似未捕获异常),因此必须处理。

97. Node.js的调试工具有哪些?如何使用--inspect参数调试?

Node.js 提供多种调试工具,用于定位代码错误和性能问题,--inspect 参数是官方推荐的调试方式。

常用调试工具
  1. Chrome DevTools:通过 --inspect 连接,支持断点、变量监视等。
  2. VS Code 内置调试器:集成IDE,操作便捷。
  3. WebStorm:专业JavaScript IDE,调试功能强大。
  4. node-inspect:命令行调试工具(需单独安装)。
  5. ndb:改进的命令行调试工具(来自Google)。
使用--inspect参数调试
  1. 启动调试模式

    # 基础用法:启动程序并开启调试
    node --inspect app.js
    # 可选:指定端口(默认9229)
    node --inspect=3000 app.js
    # 可选:程序启动时暂停(等待调试器连接)
    node --inspect-brk app.js
  2. 连接调试器

    • 打开 Chrome 浏览器,访问 chrome://inspect
    • 在“Remote Target”中找到目标程序,点击“inspect”打开调试面板。
  3. 调试操作

    • 设置断点:在代码行号处点击添加断点。
    • 监视变量:在“Watch”面板输入变量名。
    • 控制流程:使用“继续”“单步执行”“步入”“步出”按钮控制代码执行。

示例:调试 app.js

// app.js
function add(a, b) {
return a + b; // 在该行设置断点
}
const result = add(2, 3);
console.log(result);

启动命令:node --inspect app.js,在 Chrome DevTools 中观察变量 ab 的值。

98. 如何使用VS Code调试Node.js程序?

VS Code 内置Node.js调试器,支持断点调试、变量监视等功能,操作步骤如下:

步骤1:创建调试配置
  1. 打开项目文件夹,点击左侧“运行和调试”图标(或按 Ctrl+Shift+D)。
  2. 点击“创建 launch.json 文件”,选择“Node.js”环境,自动生成配置文件。
步骤2:配置launch.json

基础配置示例:

{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "启动程序",
"program": "${workspaceFolder}/app.js" // 入口文件路径
},
{
"type": "node",
"request": "attach",
"name": "附加到进程",
"port": 9229 // 对应 --inspect 端口
}
]
}
  • launch:直接启动程序并调试。
  • attach:附加到已运行的 --inspect 进程。
步骤3:开始调试
  1. 在代码行号左侧点击设置断点(出现红色圆点)。
  2. 点击调试面板的“启动调试”按钮(或按 F5)。
  3. 使用调试控制栏操作:
    • 继续(F5):执行到下一个断点。
    • 单步跳过(F10):执行当前行,不进入函数。
    • 单步调试(F11):进入当前函数内部。
    • 步出(Shift+F11):从当前函数退出。
  4. 在“变量”面板查看当前作用域的变量,在“监视”面板添加自定义监视表达式。

示例:调试HTTP服务器

// app.js
const http = require('http');
const server = http.createServer((req, res) => {
const url = req.url; // 设置断点
res.end(`Hello ${url}`);
});
server.listen(3000);

启动调试后,访问 http://localhost:3000/test,程序会在断点处暂停,可查看 req.url 的值。

99. 什么是日志?在Node.js中如何记录和管理日志?

日志是程序运行过程中产生的记录,用于跟踪流程、排查错误、分析性能。在Node.js中,日志管理需考虑分级、格式、存储和轮转。

日志的作用
  • 错误排查:记录异常堆栈和上下文。
  • 行为跟踪:记录用户操作、系统事件。
  • 性能分析:记录耗时操作的执行时间。
  • 安全审计:记录敏感操作(如登录、权限变更)。
记录和管理日志的方式
  1. 基础日志记录:使用 console 方法(简单但功能有限)。

    console.log('信息日志:用户登录'); // 普通信息
    console.warn('警告日志:磁盘空间不足'); // 警告
    console.error('错误日志:数据库连接失败'); // 错误
  2. 使用日志库:如 winstonpino,支持分级、格式化和输出到文件。

    const winston = require('winston');
    const logger = winston.createLogger({
    level: 'info', // 日志级别(info及以上会被记录)
    format: winston.format.combine(
    winston.format.timestamp(), // 添加时间戳
    winston.format.json() // JSON格式
    ),
    transports: [
    new winston.transports.Console(), // 输出到控制台
    new winston.transports.File({ filename: 'error.log', level: 'error' }), // 错误日志到文件
    new winston.transports.File({ filename: 'combined.log' }) // 所有日志到文件
    ]
    });
    // 使用日志
    logger.info('用户登录', { userId: 1, ip: '192.168.1.1' });
    logger.error('支付失败', { orderId: 100, error: '余额不足' });
  3. 日志轮转:防止日志文件过大,使用 winston-daily-rotate-file 按时间分割日志。

    npm install winston-daily-rotate-file
    const DailyRotateFile = require('winston-daily-rotate-file');
    logger.add(new DailyRotateFile({
    filename: 'app-%DATE%.log',
    datePattern: 'YYYY-MM-DD',
    maxSize: '20m', // 单个文件最大20MB
    maxFiles: '14d' // 保留14天日志
    }));
  4. 日志级别:按重要性从低到高为 sillydebugverboseinfowarnerror,可通过配置控制输出粒度。

100. 常用的Node.js日志库有哪些?请举例说明。

Node.js 生态中有多个成熟的日志库,各有特点,适用于不同场景:

1. winston
  • 特点:功能全面、可扩展、支持多传输目标(控制台、文件、数据库等)。
  • 示例
    const winston = require('winston');
    const logger = winston.createLogger({
    level: 'debug', // 记录debug及以上级别
    format: winston.format.combine(
    winston.format.colorize(), // 控制台彩色输出
    winston.format.simple() // 简化格式
    ),
    transports: [
    new winston.transports.Console(),
    new winston.transports.File({ filename: 'app.log' })
    ]
    });
    logger.debug('调试信息:变量x的值为10');
    logger.info('用户注册成功');
    logger.warn('API响应缓慢');
    logger.error('数据库连接失败', { error: '连接超时' });
2. pino
  • 特点:高性能(速度比 winston 快5-10倍)、默认JSON格式、适合生产环境。
  • 示例
    const pino = require('pino');
    const logger = pino({
    level: 'info',
    timestamp: pino.stdTimeFunctions.isoTime // ISO格式时间戳
    });
    // 输出到文件(需配合重定向)
    // const logger = pino(pino.destination('app.log'));
    logger.info({ userId: 1 }, '用户登录');
    logger.error({ err: new Error('失败') }, '操作出错');
3. morgan
  • 特点:专为HTTP请求日志设计,常与Express/Koa配合使用。
  • 示例
    const express = require('express');
    const morgan = require('morgan');
    const app = express();
    // 输出到控制台(combined格式包含详细信息)
    app.use(morgan('combined'));
    // 输出到文件
    const fs = require('fs');
    const accessLogStream = fs.createWriteStream('access.log', { flags: 'a' });
    app.use(morgan('combined', { stream: accessLogStream }));
    app.get('/',

二、120道Node.js面试题目录列表

文章序号Node.js面试题120道
1Node.js面试题及详细答案120道(01-15)
2Node.js面试题及详细答案120道(16-30)
3Node.js面试题及详细答案120道(31-42)
4Node.js面试题及详细答案120道(43-55)
5Node.js面试题及详细答案120道(56-68)
6Node.js面试题及详细答案120道(69-80)
7Node.js面试题及详细答案120道(81-92)
8Node.js面试题及详细答案120道(93-100)
9Node.js面试题及详细答案120道(101-110)
10Node.js面试题及详细答案120道(111-120)