NodeJS全栈开发面试题讲解——P1Node.js 基础与核心机制
✅ 1.1 Node.js 的事件循环原理?如何处理异步操作?
面试官您好,我理解事件循环是 Node.js 的异步非阻塞编程核心。
Node.js 构建在 V8 引擎与 libuv 库之上。虽然 Node.js 是单线程模型,但它通过事件循环(event loop)机制实现了异步 IO 和高并发能力。
🔁 事件循环核心阶段(简略版):
每一轮事件循环分为多个阶段,关键阶段有:
-
timers:执行
setTimeout
、setInterval
的回调; -
pending callbacks:处理某些系统延迟回调;
-
poll:执行 IO 回调,如网络、磁盘读取;
-
check:执行
setImmediate()
回调; -
close callbacks:如
socket.on('close')
; -
每个阶段结束后,还会处理 microtasks(如
process.nextTick()
、Promise.then()
);
🧠 异步操作如何配合事件循环?
比如我们调用异步文件读写:
fs.readFile('a.txt', () => {console.log('读文件完成');
});
-
任务由 libuv 线程池处理;
-
完成后注册回调,等待事件循环进入相应阶段;
-
在 poll 阶段执行对应的回调。
✅ 1.2 process.nextTick()、setImmediate()、Promise 的执行顺序?
这是一个非常容易被问到的陷阱问题,我用执行模型来解释它的顺序。
Node.js 将任务划分为两类:
-
Microtasks(微任务):
process.nextTick()
、Promise.then()
; -
Macrotasks(宏任务):
setTimeout
、setImmediate
;
每个事件循环阶段后,都会清空微任务队列。
📌 执行优先级(从高到低):
1. process.nextTick() // Node独有,优先级最高
2. Promise.then() // 标准微任务
3. setTimeout(fn, 0) // timers 阶段
4. setImmediate() // check 阶段
🧪 示例代码:
setTimeout(() => console.log('timeout'), 0);
setImmediate(() => console.log('immediate'));
process.nextTick(() => console.log('nextTick'));
Promise.resolve().then(() => console.log('promise'));
📌 输出顺序:
nextTick
promise
timeout
immediate
补充:过多使用
process.nextTick()
会造成主线程“饿死”(starvation),所以要慎用。
✅ 1.3 如何避免阻塞主线程?举例说明
面试官,Node.js 是单线程的,一旦主线程执行了重 CPU 运算,就会阻塞事件循环,影响并发。
🧨 示例:阻塞代码
// 计算大量斐波那契数
function fibonacci(n) {if (n <= 1) return 1;return fibonacci(n - 1) + fibonacci(n - 2);
}
fibonacci(40); // 卡住主线程
✅ 避免方法:
✅ 1. 使用 worker_threads
执行 CPU 密集型任务
const { Worker } = require('worker_threads');
new Worker('./compute.js');
✅ 2. 拆分任务(分段执行)
function heavyTask() {let count = 0;function loop() {for (let i = 0; i < 10000; i++) count++;if (count < 1e6) setImmediate(loop);}loop();
}
✅ 3. 借助外部服务(如 Redis 缓存、Nginx 静态托管)减少计算需求
✅ 1.4 Node.js 如何实现定时任务?和浏览器定时器有区别吗?
面试官,Node.js 提供和浏览器相同 API,但其实现机制完全不同。
📌 相同点:
-
setTimeout(fn, ms)
、setInterval(fn, ms)
可用; -
支持取消:
clearTimeout()
、clearInterval()
;
📌 不同点:
特性 | Node.js(libuv) | 浏览器(Web APIs) |
---|---|---|
核心实现 | libuv 的事件循环 | 浏览器引擎 + 宿主环境 |
最小时间精度 | 非实时,受事件循环影响 | 一般为 4ms 最小 |
setImmediate() | Node 独有,check 阶段执行 | 无此函数 |
📌 高级定时任务方案(Node 专属):
-
node-cron
:cron 表达式任务调度; -
Agenda / Bree
:基于数据库/文件持久化的任务调度; -
Redis 轮询 + 消息队列:实现分布式定时触发;
const cron = require('node-cron');
cron.schedule('0 0 * * *', () => console.log('每天零点执行'));
✅ 1.5 cluster 模块的原理及适用场景?如何实现负载均衡?
面试官,
cluster
是 Node.js 提供的多进程扩展机制,用于充分利用多核 CPU 提升吞吐量。
🔧 原理:
-
主进程(Master)通过
cluster.fork()
创建多个 worker 子进程; -
所有 worker 共享同一个 server 端口;
-
实际请求由主进程分发给 worker 处理;
-
每个 worker 都是独立的 Node 实例,进程隔离、内存独立;
const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;if (cluster.isMaster) {for (let i = 0; i < numCPUs; i++) cluster.fork();
} else {http.createServer((req, res) => {res.end(`Worker ${process.pid} handled request`);}).listen(3000);
}
⚖️ 负载均衡策略:
-
Linux:基于
SO_REUSEPORT
,内核自动均衡分发请求; -
Windows/macOS:Node 内部使用 Round-Robin 分发策略;
-
Node v16+ 支持与
worker_threads
混合使用,提高 CPU 利用率;
✅ 适用场景:
-
高并发 API 服务(如网关、接口层);
-
IO 与 CPU 混合负载应用;
-
可与
pm2
配合实现进程守护 + 负载均衡;
❗ 注意事项:
-
不共享内存,通信需用 IPC(如
worker.send()
); -
状态同步麻烦(需借助 Redis 等中间件);
-
cluster 并不适合细粒度计算,适合粗粒度多请求任务;
✅ 总结回顾
问题 | 核心关键词 |
---|---|
1.1 | libuv、事件循环、阶段、异步 IO |
1.2 | 微任务 vs 宏任务、执行优先级 |
1.3 | 阻塞避免、worker_threads、任务拆分 |
1.4 | Node 定时器机制、cron、高级调度 |
1.5 | cluster 原理、多进程、负载均衡策略 |