4.0 KiB
id, title, type, domain, stack, tags, level, related, week
| id | title | type | domain | stack | tags | level | related | week | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| backend.nodejs.interview | Node.js 面试题 | interview | backend |
|
|
basic |
|
|
Node.js 面试题
基础
【基础】Node 的事件循环是怎样的?
参考答案:单线程执行 JS,I/O 由 libuv 异步完成。主要阶段:timers → pending callbacks → poll → check → close callbacks;每个回调执行完后先清空 process.nextTick 队列,再清空 Promise 微任务队列。
追问:setTimeout(fn, 0) 和 setImmediate 谁先执行?→ 在主模块中顺序不确定(取决于进入事件循环时计时器是否到期);在 I/O 回调中 setImmediate 一定先执行。
【基础】Node 适合什么场景?
参考答案:I/O 密集、高并发连接:BFF、API 网关、实时推送(WebSocket / SSE)、工具链。不适合长时间的 CPU 计算,否则阻塞事件循环;需要时用 worker_threads 或拆到其他服务。
追问:怎么发现事件循环被阻塞?→ 监控事件循环延迟(perf_hooks.monitorEventLoopDelay),用 CPU profile 找热点。
【基础】Express 中间件的执行原理?
参考答案:按注册顺序组成链,每个中间件处理后调用 next() 进入下一个,不调用则请求在此结束;错误处理中间件有 4 个参数,next(err) 或 Express 5 中 async 函数抛错时跳转过去。
追问:和 Koa 的洋葱模型有什么区别?→ Koa 的 await next() 可以在后续中间件执行完后继续执行后半段逻辑,天然适合计时和统一响应处理;Express 需要监听 res 的 finish 事件实现类似效果。
进阶
【进阶】NestJS 的依赖注入有什么好处?
参考答案:类声明依赖,由容器创建和注入;便于替换实现(测试中注入假的服务)、统一生命周期管理、模块边界清晰;配合管道、守卫、拦截器形成统一规范。
追问:和 FastAPI 的 Depends 比较?→ 思想相同,FastAPI 基于函数参数声明,Nest 基于类构造函数和装饰器元数据。
【进阶】Node 服务如何处理未捕获的异常?
参考答案:请求级错误用统一错误处理中间件;进程级监听 uncaughtException / unhandledRejection 记录日志后退出,由进程管理器(容器编排 / systemd / PM2)重启;不要在未知状态下继续运行。
追问:为什么不能捕获后继续运行?→ 程序可能处于不一致的状态(连接、内存中的数据),继续运行可能产生更隐蔽的错误。
【进阶】Node 如何利用多核?
参考答案:多进程(cluster 或容器多副本 + 负载均衡)处理更多请求;worker_threads 处理 CPU 计算。服务要无状态,会话等放在 Redis。
追问:WebSocket 多实例怎么广播?→ 通过 Redis Pub/Sub 或消息队列在实例之间转发,负载均衡开启会话保持或使用支持多实例的方案。
场景题
【场景题】给 AI 应用做 BFF,你会做哪些事?
参考答案:统一鉴权、限流、request id;首屏并行聚合与降级;SSE 流式透传、断开时中止上游、超时控制、上游错误以事件形式通知;保持薄层。详见AI BFF 场景。
追问:怎么测试流式接口?→ 启动应用监听随机端口,用 fetch 读取响应,断言事件内容和顺序、错误事件和响应头,见示例测试。
【场景题】Node 服务内存持续上涨,怎么排查?
参考答案:观察堆内存趋势;在不同时间点生成堆快照对比,找增长的对象和引用链;常见原因:全局缓存无上限、事件监听未移除、闭包持有大对象、定时器未清理。修复后压测验证。
追问:线上怎么安全地拿堆快照?→ 在摘除流量的单个实例上进行,快照期间进程会暂停,注意快照可能包含敏感数据。