Node.js面试题及详细答案120题(111-120) -- 进阶与扩展篇
《前后端面试题
》专栏集合了前后端各个知识模块的面试题,包括html,javascript,css,vue,react,java,Openlayers,leaflet,cesium,mapboxGL,threejs,nodejs,mangoDB,MySQL,Linux… 。
文章目录
- 一、本文面试题目录
- 111. 什么是Node.js的子进程(Child Process)?如何创建子进程?
- 子进程的作用
- 创建子进程的方法(`child_process`模块)
- 112. 主进程和子进程如何通信?
- 通信方式(以`fork`为例)
- 示例:主进程与子进程通信
- 通信原理
- 113. 什么是Worker Threads?它和Cluster有什么区别?
- Worker Threads的作用
- Worker Threads与Cluster的区别
- 示例:使用Worker Threads
- 114. 如何在Node.js中使用TypeScript?
- 步骤1:初始化项目并安装依赖
- 步骤2:配置TypeScript(`tsconfig.json`)
- 步骤3:编写TypeScript代码
- 步骤4:运行与编译
- 步骤5:配置脚本(`package.json`)
- 115. Node.js中的模块缓存机制是怎样的?如何清除模块缓存?
- 模块缓存机制
- 示例:验证模块缓存
- 清除模块缓存
- 116. 什么是npm?如何使用npm管理依赖?
- npm的核心功能
- 使用npm管理依赖的基本操作
- 117. npm和yarn有什么区别?
- 常用命令对比
- 选择建议
- 118. 如何发布一个npm包?
- 步骤1:准备工作
- 步骤2:配置package.json
- 步骤3:发布包
- 步骤4:更新包
- 步骤5:撤销发布(谨慎使用)
- 119. Node.js的版本管理工具(如nvm)有什么作用?如何使用?
- nvm的作用
- 安装nvm
- 常用nvm命令
- 示例:为项目指定Node.js版本
- 120. 你对Node.js的未来发展有什么看法?它有哪些新特性值得关注?
- 未来发展趋势
- 值得关注的新特性(Node.js 18+)
- 总结
- 二、120道Node.js面试题目录列表
一、本文面试题目录
111. 什么是Node.js的子进程(Child Process)?如何创建子进程?
子进程(Child Process) 是由Node.js主进程创建的独立进程,用于执行耗时操作(如计算、文件处理)或调用系统命令,避免阻塞主进程的事件循环。
子进程的作用
- 利用多核CPU资源(突破Node.js单线程限制)。
- 隔离危险操作(如执行用户输入的命令)。
- 处理CPU密集型任务(避免阻塞主进程)。
创建子进程的方法(child_process
模块)
Node.js的child_process
模块提供4种创建子进程的方法:
-
spawn
:启动新进程执行命令,返回流(适合输出大量数据)。const { spawn } = require('child_process'); // 执行"ls -l"命令(Linux/Mac) const ls = spawn('ls', ['-l']);// 监听输出 ls.stdout.on('data', (data) => {console.log(`输出:${data}`); });// 监听错误 ls.stderr.on('data', (data) => {console.error(`错误:${data}`); });// 监听进程退出 ls.on('close', (code) => {console.log(`子进程退出,代码:${code}`); });
-
exec
:执行命令并缓存输出,通过回调返回结果(适合输出量小的命令)。const { exec } = require('child_process'); exec('node -v', (error, stdout, stderr) => {if (error) {console.error(`执行错误:${error.message}`);return;}if (stderr) {console.error(`命令错误:${stderr}`);return;}console.log(`Node版本:${stdout}`); });
-
execFile
:直接执行可执行文件(无需shell解析,更安全)。const { execFile } = require('child_process'); // 执行Node脚本 execFile('node', ['script.js'], (error, stdout) => {console.log(stdout); });
-
fork
:专门用于创建Node.js子进程,内置通信通道。const { fork } = require('child_process'); // 创建子进程执行worker.js const child = fork('./worker.js');
112. 主进程和子进程如何通信?
主进程与子进程通过IPC(Inter-Process Communication,进程间通信) 机制交换数据,Node.js提供了简洁的事件驱动API实现通信。
通信方式(以fork
为例)
- 发送消息:通过
send()
方法发送数据(支持JSON序列化的数据)。 - 接收消息:监听
message
事件获取数据。 - 发送错误:监听
error
事件处理异常。
示例:主进程与子进程通信
子进程(worker.js):
// 接收主进程消息
process.on('message', (msg) => {console.log(`子进程收到:${msg}`);// 向主进程发送消息if (msg === '计算') {const result = 1 + 2;process.send(`计算结果:${result}`);}
});// 子进程退出时通知主进程
process.on('exit', (code) => {process.send(`子进程退出,代码:${code}`);
});
主进程(main.js):
const { fork } = require('child_process');
const child = fork('./worker.js');// 向子进程发送消息
child.send('计算');// 接收子进程消息
child.on('message', (msg) => {console.log(`主进程收到:${msg}`);// 完成后退出子进程child.kill();
});// 监听子进程错误
child.on('error', (err) => {console.error('子进程错误:', err);
});
输出结果:
子进程收到:计算
主进程收到:计算结果:3
主进程收到:子进程退出,代码:0
通信原理
fork
创建的子进程会与主进程建立IPC通道(基于管道或socket)。- 数据通过JSON序列化传递,支持对象、数组等,但不支持函数、Buffer等特殊类型。
- 主进程可通过
child.kill()
终止子进程,子进程可通过process.exit()
主动退出。
113. 什么是Worker Threads?它和Cluster有什么区别?
Worker Threads 是Node.js v10.5.0引入的模块,用于创建多线程,允许在主线程外执行JavaScript代码,共享内存但避免阻塞事件循环。
Worker Threads的作用
- 处理CPU密集型任务(如数据分析、复杂计算)。
- 线程间通过共享内存(
SharedArrayBuffer
)高效传递数据。 - 保持单进程内的资源共享(如数据库连接)。
Worker Threads与Cluster的区别
特性 | Worker Threads | Cluster |
---|---|---|
基本单位 | 线程(同一进程内) | 进程(独立进程) |
内存共享 | 支持(通过SharedArrayBuffer ) | 不共享(进程间独立内存) |
通信方式 | postMessage (数据副本或共享内存) | IPC通道(基于消息传递) |
适用场景 | CPU密集型任务(如计算) | 并发请求处理(如HTTP服务器) |
资源占用 | 低(线程共享进程资源) | 高(独立进程) |
启动成本 | 低 | 高 |
示例:使用Worker Threads
主线程(main.js):
const { Worker } = require('worker_threads');// 创建工作线程
const worker = new Worker('./worker.js', {workerData: { num: 10 } // 初始化数据
});// 接收工作线程消息
worker.on('message', (result) => {console.log(`计算结果:${result}`); // 输出:计算结果:55
});// 监听错误
worker.on('error', (err) => {console.error('线程错误:', err);
});
工作线程(worker.js):
const { parentPort, workerData } = require('worker_threads');// 计算1到n的和(CPU密集型任务)
function sum(n) {let total = 0;for (let i = 1; i <= n; i++) {total += i;}return total;
}// 向主线程发送结果
parentPort.postMessage(sum(workerData.num));
114. 如何在Node.js中使用TypeScript?
TypeScript是JavaScript的超集,提供类型检查,可增强Node.js项目的可维护性。在Node.js中使用TypeScript的步骤如下:
步骤1:初始化项目并安装依赖
mkdir ts-node-app && cd ts-node-app
npm init -y
# 安装TypeScript及类型定义
npm install -D typescript @types/node ts-node
步骤2:配置TypeScript(tsconfig.json
)
{"compilerOptions": {"target": "ES2020", // 编译目标版本"module": "CommonJS", // 模块系统(Node.js使用CommonJS)"outDir": "./dist", // 编译输出目录"rootDir": "./src", // 源码目录"strict": true, // 启用严格类型检查"esModuleInterop": true, // 兼容ES模块"skipLibCheck": true // 跳过库类型检查},"include": ["src/**/*"], // 要编译的文件"exclude": ["node_modules"] // 排除目录
}
步骤3:编写TypeScript代码
创建src/app.ts
:
// 定义接口(类型约束)
interface User {id: number;name: string;age?: number; // 可选属性
}// 函数(带类型注解)
function greet(user: User): string {return `Hello, ${user.name} (ID: ${user.id})`;
}// 使用
const user: User = { id: 1, name: "Alice", age: 25 };
console.log(greet(user));
步骤4:运行与编译
-
直接运行(开发环境):
npx ts-node src/app.ts # 输出:Hello, Alice (ID: 1)
-
编译为JavaScript(生产环境):
npx tsc # 编译生成dist/app.js node dist/app.js # 运行编译后的文件
步骤5:配置脚本(package.json
)
{"scripts": {"dev": "ts-node src/app.ts","build": "tsc","start": "node dist/app.js"}
}
- 开发:
npm run dev
- 构建:
npm run build
- 生产运行:
npm start
115. Node.js中的模块缓存机制是怎样的?如何清除模块缓存?
Node.js会缓存已加载的模块,避免重复读取和执行文件,提高性能。
模块缓存机制
- 缓存触发时机:模块第一次被
require
或import
时,Node.js会将其编译为函数并执行,然后将结果缓存到require.cache
对象中。 - 缓存键:模块的绝对路径(即使通过不同相对路径加载同一模块,也会命中缓存)。
- 缓存内容:包含模块的导出对象(
exports
)、文件路径、模块函数等。
示例:验证模块缓存
module.js
:
console.log("模块被执行");
module.exports = { value: Math.random() };
main.js
:
// 第一次加载
const mod1 = require('./module');
// 第二次加载(命中缓存)
const mod2 = require('./module');console.log(mod1.value === mod2.value); // true(缓存导致值相同)
console.log(require.cache[require.resolve('./module')]); // 查看缓存内容
输出结果:
模块被执行(仅输出一次)
true
清除模块缓存
如需重新加载模块(如开发环境热更新),可手动删除require.cache
中的缓存项:
// 清除单个模块缓存
delete require.cache[require.resolve('./module')];// 重新加载模块(会重新执行模块代码)
const mod3 = require('./module');
console.log(mod3.value); // 新的随机值(与mod1不同)
注意:
- 清除缓存后,模块会被重新执行,可能导致副作用(如重复初始化)。
- ES模块(
import
)的缓存机制类似,但清除方式不同(需通过import.meta.url
和moduleCache
,且不同Node.js版本实现有差异)。
116. 什么是npm?如何使用npm管理依赖?
npm(Node Package Manager) 是Node.js的包管理工具,用于安装、发布、管理JavaScript模块,是Node.js生态的核心组成部分。
npm的核心功能
- 下载第三方包(如
express
、lodash
)。 - 管理项目依赖(开发依赖、生产依赖)。
- 执行项目脚本(如启动、测试、构建)。
- 发布自己的包到npm仓库。
使用npm管理依赖的基本操作
-
初始化项目(生成
package.json
):npm init -y # -y 跳过交互,使用默认配置
-
安装依赖:
-
生产依赖(项目运行必需):
npm install express # 简写:npm i express
依赖会被添加到
package.json
的dependencies
中。 -
开发依赖(仅开发时需要,如TypeScript、测试工具):
npm install --save-dev jest # 简写:npm i -D jest
依赖会被添加到
package.json
的devDependencies
中。
-
-
查看依赖:
npm list # 查看所有依赖(树形结构) npm list express # 查看指定依赖版本
-
更新依赖:
npm update express # 更新到符合版本范围的最新版 npm install express@latest # 强制更新到最新版
-
卸载依赖:
npm uninstall express # 卸载生产依赖 npm uninstall -D jest # 卸载开发依赖
-
安装指定版本:
npm install lodash@4.17.21 # 安装4.17.21版本
-
执行脚本(在
package.json
的scripts
中定义):{"scripts": {"start": "node app.js","test": "jest"} }
执行:
npm run start # 或 npm start(start是特殊脚本,可省略run) npm run test
117. npm和yarn有什么区别?
npm和yarn都是Node.js的包管理工具,yarn最初作为npm的替代品出现,两者功能相似但存在一些差异:
特性 | npm(v7+) | yarn |
---|---|---|
发布时间 | 2010年(较早) | 2016年(由Facebook等公司开发) |
安装速度 | 较快(v7+优化了缓存和并行安装) | 更快(早期并行安装优势明显,现在差异缩小) |
依赖锁定 | 使用package-lock.json | 使用yarn.lock |
缓存机制 | 有缓存(~/.npm ) | 有缓存(~/.yarn/cache ),支持离线安装 |
命令差异 | npm install 、npm run | yarn add 、yarn (替代npm run ) |
安全性 | 自动检查依赖漏洞(npm audit ) | 内置依赖验证机制 |
工作区支持 | 支持(workspaces 字段) | 原生支持(更早实现) |
流行度 | 最广泛(Node.js默认) | 广泛(尤其在前端项目) |
常用命令对比
功能 | npm命令 | yarn命令 |
---|---|---|
初始化项目 | npm init | yarn init |
安装生产依赖 | npm install <pkg> | yarn add <pkg> |
安装开发依赖 | npm install -D <pkg> | yarn add -D <pkg> |
全局安装 | npm install -g <pkg> | yarn global add <pkg> |
安装所有依赖 | npm install | yarn install (或简写yarn ) |
卸载依赖 | npm uninstall <pkg> | yarn remove <pkg> |
执行脚本 | npm run <script> | yarn <script> |
发布包 | npm publish | yarn publish |
选择建议
- 若团队已习惯npm,或项目简单,使用npm即可(无需额外学习成本)。
- 若追求更快的安装速度、更稳定的依赖锁定,或需要工作区功能,可选择yarn。
- 两者均可通过
package-lock.json
或yarn.lock
确保依赖版本一致,避免“版本地狱”。
118. 如何发布一个npm包?
发布npm包是将自己开发的模块共享到npm仓库的过程,供其他开发者通过npm install
使用,步骤如下:
步骤1:准备工作
-
注册npm账号
- 访问npm官网注册账号,或通过命令行注册:
npm adduser # 按提示输入用户名、密码、邮箱
- 访问npm官网注册账号,或通过命令行注册:
-
登录npm
npm login # 输入账号信息(确保已切换到官方源,非淘宝镜像)
-
创建包项目
mkdir my-utils && cd my-utils npm init -y # 生成package.json,需完善包信息
-
编写包代码
创建入口文件(如index.js
):// 示例:实现一个简单的加法函数 function add(a, b) {return a + b; }module.exports = { add };
步骤2:配置package.json
关键配置项说明:
{"name": "my-utils-demo", // 包名(必须唯一,可在npm官网查询是否被占用)"version": "1.0.0", // 版本号(遵循语义化版本:major.minor.patch)"description": "一个简单的工具函数库", // 包描述"main": "index.js", // 入口文件"author": "Your Name", // 作者"license": "MIT", // 开源协议"keywords": ["utils", "add"] // 搜索关键词
}
步骤3:发布包
npm publish # 发布到npm仓库
- 首次发布成功后,可在npm官网搜索包名(如
my-utils-demo
)查看。 - 若发布失败,可能原因:包名已被占用、未登录、网络问题。
步骤4:更新包
-
修改代码后,更新版本号:
npm version patch # 修复bug:1.0.0 → 1.0.1 # 或 npm version minor(新增功能:1.0.0 → 1.1.0) # 或 npm version major( breaking change:1.0.0 → 2.0.0)
-
重新发布:
npm publish
步骤5:撤销发布(谨慎使用)
npm unpublish my-utils-demo@1.0.0 # 撤销指定版本
# 注意:发布超过24小时的包无法撤销,避免影响依赖该包的项目
119. Node.js的版本管理工具(如nvm)有什么作用?如何使用?
nvm(Node Version Manager) 是Node.js的版本管理工具,用于在同一台设备上切换不同版本的Node.js,解决不同项目对Node.js版本的依赖冲突。
nvm的作用
- 同时安装多个Node.js版本(如v14、v16、v18)。
- 快速切换当前使用的Node.js版本。
- 为不同项目指定特定的Node.js版本。
- 避免权限问题(无需sudo安装全局包)。
安装nvm
-
Linux/macOS:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash # 或使用wget wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
安装后重启终端,或执行
source ~/.bashrc
(根据shell类型调整)。 -
Windows:
使用nvm的Windows版本nvm-windows,下载安装包并按向导操作。
常用nvm命令
-
查看已安装版本
nvm ls
-
安装指定版本
nvm install 18.18.0 # 安装v18.18.0 nvm install lts # 安装最新LTS版本 nvm install node # 安装最新稳定版
-
切换使用版本
nvm use 18.18.0 # 切换到v18.18.0 nvm use lts # 切换到LTS版本
-
设置默认版本
nvm alias default 18.18.0 # 每次打开终端默认使用v18.18.0
-
卸载版本
nvm uninstall 14.21.3 # 卸载v14.21.3
-
查看可安装的版本
nvm ls-remote # 列出远程仓库所有版本
示例:为项目指定Node.js版本
在项目根目录创建.nvmrc
文件,写入版本号:
echo "18.18.0" > .nvmrc
进入项目时,执行nvm use
会自动切换到.nvmrc
指定的版本。
120. 你对Node.js的未来发展有什么看法?它有哪些新特性值得关注?
Node.js作为JavaScript的服务器端运行时,凭借非阻塞I/O和丰富的生态,已成为后端开发的重要选择。其未来发展将围绕性能优化、生态扩展和开发体验提升展开。
未来发展趋势
-
性能持续提升
Node.js核心团队持续优化V8引擎集成和事件循环机制,未来在异步I/O、内存管理等方面将进一步突破,缩小与传统编译型语言的性能差距。 -
Web标准对齐
更多浏览器API(如Fetch API
、Streams API
)将被原生支持,减少前后端代码差异,降低全栈开发成本。 -
生态多元化
从传统Web服务向边缘计算、物联网(IoT)、Serverless等领域扩展,成为跨平台开发的核心工具。 -
TypeScript深度融合
官方对TypeScript的支持将加强,可能推出更便捷的类型检查工具或内置类型定义。
值得关注的新特性(Node.js 18+)
-
内置Fetch API(v18+)
无需依赖node-fetch
等第三方库,原生支持浏览器兼容的fetch
:// 示例:使用内置fetch const response = await fetch('https://api.example.com'); const data = await response.json(); console.log(data);
-
内置测试运行器(v18.13+,实验性)
无需Jest
或Mocha
,可直接运行测试:// test.js import { test, assert } from 'node:test';test('加法测试', () => {assert.strictEqual(1 + 2, 3); });
运行:
node --test test.js
-
ESM模块系统稳定化
原生支持ES模块(import/export
),与CommonJS的互操作性不断优化,逐步成为主流模块格式。 -
单可执行文件(Single Executable Applications)
可将Node.js应用打包为单个可执行文件(.exe
或二进制文件),简化部署流程(v20+实验性支持)。 -
Worker Threads增强
线程间通信效率提升,共享内存API更完善,更好地支持CPU密集型任务。
总结
Node.js将继续在后端开发、全栈开发领域保持活力,其发展重点是提升性能、标准化API和扩展应用场景。开发者应关注LTS版本的新特性,尤其是内置API和模块系统的演进,以提高开发效率。
二、120道Node.js面试题目录列表
文章序号 | Node.js面试题120道 |
---|---|
1 | Node.js面试题及详细答案120道(01-15) |
2 | Node.js面试题及详细答案120道(16-30) |
3 | Node.js面试题及详细答案120道(31-42) |
4 | Node.js面试题及详细答案120道(43-55) |
5 | Node.js面试题及详细答案120道(56-68) |
6 | Node.js面试题及详细答案120道(69-80) |
7 | Node.js面试题及详细答案120道(81-92) |
8 | Node.js面试题及详细答案120道(93-100) |
9 | Node.js面试题及详细答案120道(101-110) |
10 | Node.js面试题及详细答案120道(111-120) |