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… 。

文章目录
- 一、本文面试题目录
- 二、120道Node.js面试题目录列表
一、本文面试题目录
93. Node.js中的错误类型有哪些?如何捕获全局错误?
Node.js 中的错误可分为多种类型,不同类型对应不同的场景,捕获全局错误能避免程序意外崩溃。
常见错误类型
Error:所有错误的基类,包含错误消息(message)和堆栈跟踪(stack)。SyntaxError:语法错误(如代码拼写错误),通常在程序启动时抛出。// 示例:缺少括号导致语法错误 function test() { console.log('test') // 缺少 }TypeError:类型错误(如调用非函数对象)。const num = 123; num(); // TypeError: num is not a functionReferenceError:引用错误(如使用未定义的变量)。console.log(undefinedVar); // ReferenceError: undefinedVar is not definedRangeError:范围错误(如数组长度为负数)。const arr = new Array(-1); // RangeError: Invalid array length- 自定义错误:通过继承
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 处理异步错误,但需注意其适用范围。
处理异步错误的方式
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();Promise链式调用 +
catch():fs.readFile('nonexistent.txt', 'utf8') .then(data => console.log(data)) .catch(err => console.error('读取失败:', err.message));
try/catch 能捕获的错误
同步错误:如
TypeError、ReferenceError等。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();
处理方式
局部处理:为每个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();全局处理:监听
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 参数是官方推荐的调试方式。
常用调试工具
- Chrome DevTools:通过
--inspect连接,支持断点、变量监视等。 - VS Code 内置调试器:集成IDE,操作便捷。
- WebStorm:专业JavaScript IDE,调试功能强大。
node-inspect:命令行调试工具(需单独安装)。ndb:改进的命令行调试工具(来自Google)。
使用--inspect参数调试
启动调试模式:
# 基础用法:启动程序并开启调试 node --inspect app.js # 可选:指定端口(默认9229) node --inspect=3000 app.js # 可选:程序启动时暂停(等待调试器连接) node --inspect-brk app.js连接调试器:
- 打开 Chrome 浏览器,访问
chrome://inspect。 - 在“Remote Target”中找到目标程序,点击“inspect”打开调试面板。
- 打开 Chrome 浏览器,访问
调试操作:
- 设置断点:在代码行号处点击添加断点。
- 监视变量:在“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 中观察变量 a、b 的值。
98. 如何使用VS Code调试Node.js程序?
VS Code 内置Node.js调试器,支持断点调试、变量监视等功能,操作步骤如下:
步骤1:创建调试配置
- 打开项目文件夹,点击左侧“运行和调试”图标(或按
Ctrl+Shift+D)。 - 点击“创建 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:开始调试
- 在代码行号左侧点击设置断点(出现红色圆点)。
- 点击调试面板的“启动调试”按钮(或按
F5)。 - 使用调试控制栏操作:
- 继续(
F5):执行到下一个断点。 - 单步跳过(
F10):执行当前行,不进入函数。 - 单步调试(
F11):进入当前函数内部。 - 步出(
Shift+F11):从当前函数退出。
- 继续(
- 在“变量”面板查看当前作用域的变量,在“监视”面板添加自定义监视表达式。
示例:调试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中,日志管理需考虑分级、格式、存储和轮转。
日志的作用
- 错误排查:记录异常堆栈和上下文。
- 行为跟踪:记录用户操作、系统事件。
- 性能分析:记录耗时操作的执行时间。
- 安全审计:记录敏感操作(如登录、权限变更)。
记录和管理日志的方式
基础日志记录:使用
console方法(简单但功能有限)。console.log('信息日志:用户登录'); // 普通信息 console.warn('警告日志:磁盘空间不足'); // 警告 console.error('错误日志:数据库连接失败'); // 错误使用日志库:如
winston或pino,支持分级、格式化和输出到文件。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: '余额不足' });日志轮转:防止日志文件过大,使用
winston-daily-rotate-file按时间分割日志。npm install winston-daily-rotate-fileconst DailyRotateFile = require('winston-daily-rotate-file'); logger.add(new DailyRotateFile({ filename: 'app-%DATE%.log', datePattern: 'YYYY-MM-DD', maxSize: '20m', // 单个文件最大20MB maxFiles: '14d' // 保留14天日志 }));日志级别:按重要性从低到高为
silly、debug、verbose、info、warn、error,可通过配置控制输出粒度。
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('/',
浙公网安备 33010602011771号