序章
Node.js:从 JavaScript 到系统调用的全链路穿透
第一阶段:重新理解 Node.js 的本质
- Node.js 不是语言,也不是框架,它是运行时(Runtime)
基于 V8 的 JavaScript 执行环境 + libuv 的异步 I/O + C++ 绑定 - CommonJS 模块系统:
require()的加载流程三步走
路径分析 → 文件定位 → 编译执行(.js、.json、.node) - 模块缓存:
require为什么是同步且高效的?Module._cache如何避免重复加载?热更新的陷阱 __filename与__dirname:它们从哪来?
在编译阶段被注入的“魔法变量”exportsvsmodule.exports:导出机制的常见误解
引用赋值 vs 对象属性修改
第二阶段:深入事件循环(Event Loop)
- libuv 的事件循环架构:6 个阶段的精确顺序
timers → I/O callbacks → idle/prepare → poll → check → close setTimeout(fn, 0)真的是立即执行吗?
至少等待一个事件循环周期,可能更久setImmediate()vssetTimeout(fn, 0):谁先执行?
在 I/O 回调中注册时,setImmediate优先;否则不确定process.nextTick():不是事件循环的一部分,而是“微任务”
它在每个阶段之间清空,优先级高于 Promise- 事件循环中的“饥饿”问题:CPU 密集任务如何阻塞 I/O?
单线程模型的致命弱点,Worker Threads 的必要性
第三阶段:掌握核心模块与底层机制
Buffer:为什么需要它?JS 字符串无法处理二进制
基于 C++uint8_t[]的内存分配,allocvsallocUnsafeStream:背压(Backpressure)机制是如何工作的?highWaterMark、_read()、_write()、可读/可写流的内部队列fs模块:同步 vs 异步 vs 流式读取readFileSync阻塞主线程,createReadStream支持大文件child_process:spawn、exec、fork的本质区别fork创建 IPC 通道,用于主进程与子进程通信cluster模块:如何利用多核 CPU?
主进程监听端口,子进程共享 socket(SO_REUSEADDR)
第四阶段:穿透 V8 与性能优化
- V8 内存限制:为什么 Node.js 默认堆内存只有 ~1.4GB?
32 位指针限制,可通过--max-old-space-size调整 - 内存泄漏排查:
heapdump+Chrome DevTools
如何分析 retainers,找到未释放的闭包或缓存? - 性能分析:
--prof+--prof-process生成火焰图
识别热点函数,优化关键路径 - C++ 插件:
N-API为何能解决 ABI 兼容问题?
抽象层隔离 V8 变更,实现跨版本兼容 Atomics与SharedArrayBuffer:多线程共享内存
Worker Threads 中的原子操作与同步机制
第五阶段:理解模块加载与包管理
- 模块解析算法:Node.js 如何查找
node_modules?
从当前目录向上递归,支持package.json的main字段 require.resolve():只解析路径,不执行模块
用于静态分析、插件发现- ES Modules in Node.js:
.mjs与type: "module"
静态分析、顶层await、与 CommonJS 的互操作(createRequire) node_modules扁平化:npm/yarn/pnpm 的不同策略
pnpm 的硬链接 + 元数据文件如何节省磁盘空间?NODE_PATH与--preserve-symlinks:非标准路径加载
微前端、monorepo 中的模块解析难题
第六阶段:生产环境高阶实践
- 进程守护:
systemd、pm2、forever的对比pm2的负载均衡、日志管理、热重载 - 错误处理:未捕获异常与未处理 Promise 拒绝
process.on('uncaughtException')的风险与正确用法 - 信号处理:
SIGTERMvsSIGKILL,优雅关闭
清理数据库连接、关闭服务器、退出进程 - 安全加固:
helmet、输入验证、防止 DoS
HTTP 头部、速率限制、沙箱执行 - 可观测性:日志、监控、追踪(OpenTelemetry)
结构化日志、Prometheus 指标暴露
第七阶段:连接操作系统与网络底层
net模块:TCP 服务器的pause()与resume()
流量控制、背压传递dgram模块:UDP 的无连接通信
DNS 查询、实时音视频传输http模块:Parser 如何处理请求头与 Body?
基于llparse的状态机解析- HTTPS 与 TLS:
crypto模块的角色
证书、密钥交换、加密套件 - DNS 查询:
dns.lookup()vsdns.resolve()
前者走系统配置(/etc/nsswitch.conf),后者直接查 DNS 服务器