Node.js 与后端框架学习路线 / Node.js and Backend Frameworks Learning Path
📅 创建时间:2026-07-28 🏷️ 标签:#Nodejs #Express #Fastify #Backend #ServerSide 📚 前置知识:[[../01-javascript-and-typescript/03-async-and-event-loop]]
📋 本章目标
- 理解 Node.js 运行时架构(V8 + libuv)与事件驱动模型
- 掌握 Node.js 核心抽象:EventEmitter、Stream、Buffer、模块系统
- 理解 Express 中间件洋葱模型与请求生命周期
- 能够在 Express、Fastify、Hono、NestJS 之间做出合理选型
- 掌握后端分层架构设计与 API 设计原则
- 理解进程管理、错误处理、优雅关闭与生产部署策略
第1部分:Node.js 在 Web 技术栈中的位置
1.1 Node.js 解决了什么问题
┌─────────────────────────────────────────────────────────────┐
│ 没有 Node.js 之前 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 前端 JavaScript ←────────── 鸿沟 ──────────→ 后端 │
│ (浏览器中的 DOM 操作) (Python/Ruby/Java/PHP) │
│ │
│ 问题: │
│ • 前后端使用不同语言 → 类型定义需重复维护 │
│ • 前端开发者无法写后端代码 → 人力瓶颈 │
│ • JavaScript 的异步模型天然适合 I/O 密集场景,但被限制在浏览器│
│ │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 有了 Node.js 之后 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 浏览器 JS ──── Node.js ──── 数据库 / 文件系统 / 网络 │
│ (DOM/Web API) (fs/net/http) (PostgreSQL/Redis/Kafka) │
│ │
│ 优势: │
│ • 全栈 TypeScript → 共享类型定义与验证逻辑 │
│ • 事件驱动 + 非阻塞 I/O → 高并发低开销 │
│ • npm 生态 → 最大的包管理系统 │
│ • 同一语言贯穿前端、BFF、后端、CLI 工具和构建脚本 │
│ │
└─────────────────────────────────────────────────────────────┘1.2 Node.js 适合什么,不适合什么
┌─────────────────────────────────────────────────────────────┐
│ Node.js 适用性决策 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ✅ 最佳场景: │
│ • I/O 密集的 API 服务(数据库查询、第三方 API 调用) │
│ • BFF(Backend For Frontend)——为前端定制的聚合层 │
│ • 实时应用(WebSocket、SSE、长轮询) │
│ • 构建工具与 CLI(Vite、ESLint、prettier) │
│ • 微服务与 Serverless 函数 │
│ • 代理与网关(请求转发、协议转换) │
│ │
│ ⚠️ 需要额外设计: │
│ • CPU 密集型计算(图像处理、加密、大数据排序) │
│ → 使用 Worker Threads、原生扩展(napi-rs)、或独立服务 │
│ • 长生命周期的内存状态管理 │
│ → 注意 GC 策略与内存泄漏排查 │
│ • 多线程共享内存并发 │
│ → 使用 SharedArrayBuffer + Atomics(有限场景) │
│ │
│ ❌ 通常不适合: │
│ • 硬实时系统(如飞行控制、医疗设备) │
│ • 极度 CPU 密集且无法拆分的计算任务 │
│ • 需要操作系统级线程调度的业务逻辑 │
│ │
└─────────────────────────────────────────────────────────────┘第2部分:Node.js 运行时架构全景
2.1 三大支柱:V8 + libuv + 绑定层
┌─────────────────────────────────────────────────────────────┐
│ Node.js 运行时架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 你的 JavaScript 代码 │ │
│ │ const http = require('http') │ │
│ │ fs.readFile('data.txt', (err, data) => {...}) │ │
│ └─────────────────────────┬───────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Node.js Core Library (JS 层) │ │
│ │ http / fs / net / stream / buffer / crypto / ... │ │
│ └─────────────────────────┬───────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Node.js C++ Bindings (node-binding 层) │ │
│ │ 将 JS 调用翻译为底层 C/C++ 操作 │ │
│ └──────────────┬──────────────────┬───────────────────┘ │
│ ↓ ↓ │
│ ┌──────────────────────┐ ┌──────────────────────────┐ │
│ │ V8 │ │ libuv │ │
│ │ • JS 编译与执行 │ │ • 事件循环 │ │
│ │ • 垃圾回收 │ │ • 线程池(默认 4 线程) │ │
│ │ • 隐藏类优化 │ │ • 跨平台异步 I/O │ │
│ │ • JIT 编译 │ │ • epoll/kqueue/IOCP │ │
│ └──────────────────────┘ └──────────────────────────┘ │
│ │
│ 其他底层依赖: │
│ • OpenSSL (TLS/加密) • zlib (压缩) │
│ • c-ares (DNS 解析) • http-parser (HTTP 解析) │
│ │
└─────────────────────────────────────────────────────────────┘2.2 Event Loop 深入:libuv 的六个阶段
┌─────────────────────────────────────────────────────────────┐
│ libuv 事件循环六阶段 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ │
│ │ timers │ setTimeout / setInterval 回调 │
│ └────┬─────┘ │
│ ↓ │
│ ┌──────────────┐ │
│ │ pending │ 延迟到下一轮的 I/O 回调 │
│ │ callbacks │ (系统操作,如 TCP 错误) │
│ └────┬─────────┘ │
│ ↓ │
│ ┌──────────────┐ │
│ │ idle, │ libuv 内部使用 │
│ │ prepare │ │
│ └────┬─────────┘ │
│ ↓ │
│ ┌──────────────┐ ┌─────────────────┐ │
│ │ poll │ ───→ │ 执行 I/O 回调 │ │
│ │ (核心阶段) │ │ (fs, net, http) │ │
│ │ │ ←─── │ 如队列为空则阻塞 │ │
│ └────┬─────────┘ └─────────────────┘ │
│ ↓ │
│ ┌──────────────┐ │
│ │ check │ setImmediate 回调 │
│ └────┬─────────┘ │
│ ↓ │
│ ┌──────────────┐ │
│ │ close │ close 事件回调 (socket.on('close')) │
│ │ callbacks │ │
│ └────┬─────────┘ │
│ ↓ │
│ 回到 timers(或退出) │
│ │
│ ⚡ 每个阶段之间:process.nextTick + microtasks 清空 │
│ │
└─────────────────────────────────────────────────────────────┘关键理解:setTimeout(fn, 0) 不会在 0ms 后执行——它会在下一个 timers 阶段执行。而 setImmediate(fn) 在 check 阶段执行。两者之间,process.nextTick 和 microtasks 总是最先运行。
2.3 微任务插入点
┌─────────────────────────────────────────────────────────────┐
│ 事件循环中的微任务插入 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 每个阶段之间: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 1. process.nextTick 队列 → 全部清空 │ │
│ │ 2. microtasks 队列 (Promise, queueMicrotask) → 清空 │ │
│ │ 3. 进入下一阶段 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 执行顺序示例: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ setTimeout(() => console.log('timeout'), 0) │ │
│ │ setImmediate(() => console.log('immediate')) │ │
│ │ Promise.resolve().then(() => console.log('promise')) │ │
│ │ process.nextTick(() => console.log('nextTick')) │ │
│ │ console.log('sync') │ │
│ │ │ │
│ │ 输出顺序: │ │
│ │ sync → nextTick → promise → timeout/immediate │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘第3部分:Node.js 核心抽象
3.1 EventEmitter:一切事件的源头
┌─────────────────────────────────────────────────────────────┐
│ EventEmitter 模式 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 几乎所有 Node.js 核心模块都继承自 EventEmitter: │
│ • http.Server → 'request', 'connection', 'close' │
│ • fs.ReadStream → 'data', 'end', 'error' │
│ • process → 'exit', 'uncaughtException', 'SIGTERM' │
│ • net.Socket → 'data', 'connect', 'drain' │
│ │
│ 核心 API: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ const { EventEmitter } = require('events') │ │
│ │ │ │
│ │ class MyService extends EventEmitter { │ │
│ │ start() { │ │
│ │ this.emit('started', { time: Date.now() }) │ │
│ │ } │ │
│ │ } │ │
│ │ │ │
│ │ const svc = new MyService() │ │
│ │ svc.on('started', (data) => {...}) // 监听 │ │
│ │ svc.once('started', (data) => {...}) // 单次 │ │
│ │ svc.emit('started', payload) // 触发 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ⚠️ 注意:EventEmitter 的 listener 默认同步执行 │
│ emit 不会等待 listener 中的 async 函数完成 │
│ │
└─────────────────────────────────────────────────────────────┘3.2 Stream:处理数据的正确方式
┌─────────────────────────────────────────────────────────────┐
│ Node.js Stream 体系 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────────┐ ┌──────────┐ │
│ │ Readable │ ──→ │ Transform │ ──→ │ Writable │ │
│ │ (来源) │ │ (转换) │ │ (目标) │ │
│ └──────────┘ └──────────────┘ └──────────┘ │
│ │
│ 四种 Stream 类型: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Readable → fs.createReadStream, http.IncomingMsg │ │
│ │ Writable → fs.createWriteStream, http.ServerResp │ │
│ │ Duplex → net.Socket (可读可写) │ │
│ │ Transform → zlib.createGzip, crypto 加密流 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 为什么用 Stream 而不是一次性读入内存: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ❌ fs.readFile('/path/to/10gb.csv') │ │
│ │ → 内存爆炸,进程 OOM │ │
│ │ │ │
│ │ ✅ fs.createReadStream('/path/to/10gb.csv') │ │
│ │ .pipe(csvParser) │ │
│ │ .pipe(transformStream) │ │
│ │ .pipe(dbWriteStream) │ │
│ │ → 内存占用恒定,逐块处理 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 关键模式:背压(Backpressure) │
│ • 当 Writable 消费速度 < Readable 生产速度时 │
│ • `write()` 返回 false → 暂停读取 │
│ • 'drain' 事件 → 恢复读取 │
│ • `pipe()` 自动处理背压 │
│ │
└─────────────────────────────────────────────────────────────┘3.3 Buffer:JavaScript 与二进制世界的桥梁
// Buffer 是 Node.js 中专用于处理二进制数据的类型
// 它是 Uint8Array 的子类,但提供了更丰富的编码/解码方法
// 创建 Buffer
const buf1 = Buffer.from('Hello Node.js', 'utf-8')
const buf2 = Buffer.alloc(1024) // 分配 1KB 零填充内存
const buf3 = Buffer.from([0x48, 0x65, 0x6c, 0x6c, 0x6f]) // Hello
// 常见场景
const header = Buffer.alloc(4)
header.writeUInt32BE(payloadLength, 0) // 写入 4 字节大端整数
// 注意:Buffer.allocUnsafe 更快但不初始化内存
// 可能泄露之前的内存数据,仅在立即覆盖时使用3.4 模块系统:CJS 与 ESM 的互操作
┌─────────────────────────────────────────────────────────────┐
│ CJS vs ESM 互操作 │
├─────────────────────────────────────────────────────────────┤
│ │
│ CJS (require) ESM (import) │
│ ┌─────────────────────┐ ┌─────────────────────┐ │
│ │ 同步加载 │ │ 异步加载 │ │
│ │ 运行时解析 │ │ 编译时解析 │ │
│ │ module.exports │ │ export default/named│ │
│ │ require() 可在任何处│ │ import 只能在顶层 │ │
│ │ 不可 tree-shake │ │ 可 tree-shake │ │
│ │ this === module.exp │ │ this === undefined │ │
│ └─────────────────────┘ └─────────────────────┘ │
│ │
│ 互操作规则: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ESM → CJS:可以直接 import(default import 对应 │ │
│ │ module.exports) │ │
│ │ CJS → ESM:可以使用 await import() 动态导入 │ │
│ │ 但不能用 require() 加载 ESM 模块 │ │
│ │ │ │
│ │ package.json 关键字段: │ │
│ │ "type": "module" → .js 文件作为 ESM 解析 │ │
│ │ "exports": { → 定义包入口(替代 main) │ │
│ │ ".": { │ │
│ │ "import": "./dist/index.mjs", │ │
│ │ "require": "./dist/index.cjs" │ │
│ │ } │ │
│ │ } │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘第4部分:框架选型全景
4.1 框架定位图谱
┌─────────────────────────────────────────────────────────────┐
│ Node.js 框架定位图 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 抽象程度 ↑ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ NestJS ───────────── 企业级、DI、模块化、装饰器 │ │
│ │ │ 全面抽象,适合大型团队 │ │
│ │ │ │ │
│ │ ├── Fastify ──────── 高性能、Schema 驱动、插件化 │ │
│ │ │ 适合注重吞吐和类型安全的新项目 │ │
│ │ │ │ │
│ │ ├── Express ──────── 生态最成熟、极简灵活 │ │
│ │ │ 适合快速原型、中小 API 和渐进式项目 │ │
│ │ │ │ │
│ │ ├── Hono ─────────── 超轻量、Edge 优先 │ │
│ │ │ 适合 Serverless、Edge Functions、极致性能 │ │
│ │ │ │ │
│ │ └── node:http ────── 零抽象、完全控制 │ │
│ │ 适合学习、基础设施组件 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘4.2 选型决策矩阵
┌─────────────────────────────────────────────────────────────┐
│ 框架选型决策矩阵 │
├─────────────────────────────────────────────────────────────┤
│ │
│ │ 考量因素 │ Express │ Fastify │ NestJS │ Hono │
│ ├──────────────┼────────┼────────┼────────┼──────────┤
│ │ 生态成熟度 │ ⭐⭐⭐⭐⭐ │ ⭐⭐⭐⭐ │ ⭐⭐⭐⭐ │ ⭐⭐⭐ │
│ │ 性能(吞吐) │ ⭐⭐⭐ │ ⭐⭐⭐⭐⭐ │ ⭐⭐⭐ │ ⭐⭐⭐⭐⭐ │
│ │ 学习曲线 │ ⭐(易) │ ⭐⭐ │ ⭐⭐⭐⭐ │ ⭐(易) │
│ │ TypeScript │ ⭐⭐ │ ⭐⭐⭐⭐ │ ⭐⭐⭐⭐⭐ │ ⭐⭐⭐⭐ │
│ │ 插件/中间件 │ ⭐⭐⭐⭐⭐ │ ⭐⭐⭐⭐ │ ⭐⭐⭐⭐⭐ │ ⭐⭐⭐ │
│ │ Edge/Serverless│ ⭐⭐ │ ⭐⭐ │ ⭐⭐ │ ⭐⭐⭐⭐⭐ │
│ │ 大型项目治理 │ ⭐⭐ │ ⭐⭐⭐ │ ⭐⭐⭐⭐⭐ │ ⭐⭐ │
│ │ 社区活跃度 │ ⭐⭐⭐⭐⭐ │ ⭐⭐⭐⭐ │ ⭐⭐⭐⭐ │ ⭐⭐⭐ │
│ │
│ 推荐选择: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ • 学习后端 → Express(理解 HTTP 和中间件本质) │ │
│ │ • 新项目 API → Fastify(性能 + TS 类型安全) │ │
│ │ • 大型企业 → NestJS(DI + 模块化 + 架构规范) │ │
│ │ • Serverless / Edge → Hono(极致轻量) │ │
│ │ • 快速原型 → Express(中间件生态最丰富) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘第5部分:推荐分层架构
5.1 四层架构
┌─────────────────────────────────────────────────────────────┐
│ 后端四层架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ HTTP / Controller 层 │ │
│ │ 职责:协议转换、输入验证、认证上下文、响应格式化 │ │
│ │ 依赖:框架(Express Request/Response) │ │
│ └─────────────────────────┬───────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Application Service 层 │ │
│ │ 职责:用例编排、事务管理、权限校验、DTO 映射 │ │
│ │ 依赖:Domain 层接口(不依赖框架) │ │
│ └─────────────────────────┬───────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Domain / Business Logic 层 │ │
│ │ 职责:业务规则、实体、值对象、领域事件 │ │
│ │ 依赖:无(纯 TypeScript,不依赖任何框架/库) │ │
│ └─────────────────────────┬───────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Infrastructure / Adapter 层 │ │
│ │ 职责:数据库访问、消息队列、外部 API、文件存储 │ │
│ │ 依赖:具体 SDK/ORM/Driver │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘5.2 关键原则
业务规则不应依赖 Express Request、数据库 ORM Model 或某个消息队列 SDK。Controller 负责协议转换,Service 负责编排,Domain 保持独立。
第6部分:一个请求的完整生命周期
┌─────────────────────────────────────────────────────────────┐
│ 请求处理标准流程 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 解析与验证 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ • URL 参数 → 路由匹配 │ │
│ │ • Query String → 解析与类型转换 │ │
│ │ • Headers → CORS、Content-Type、Accept │ │
│ │ • Body → 解析 (JSON/form/multipart) → Zod 验证 │ │
│ └─────────────────────────────────────────────────────┘ │
│ ↓ │
│ 2. 认证与授权 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ • 提取 Token / Session ID │ │
│ │ • 验证身份(JWT verify / Session lookup) │ │
│ │ • 检查资源级权限(RBAC / ABAC) │ │
│ └─────────────────────────────────────────────────────┘ │
│ ↓ │
│ 3. 业务处理 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ • 执行领域规则 │ │
│ │ • 事务管理 + 幂等控制 │ │
│ │ • 缓存检查与更新 │ │
│ └─────────────────────────────────────────────────────┘ │
│ ↓ │
│ 4. 响应映射 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ • 领域对象 → DTO → JSON 响应 │ │
│ │ • 设置状态码、Headers(ETag、Location) │ │
│ │ • 标准化错误格式 │ │
│ └─────────────────────────────────────────────────────┘ │
│ ↓ │
│ 5. 可观测性 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ • 结构化日志 (requestId, userId, duration, status) │ │
│ │ • Metrics (request count, latency, error rate) │ │
│ │ • Trace (跨服务追踪) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘第7部分:本模块文章导航
┌─────────────────────────────────────────────────────────────┐
│ Node.js 模块文章导航 │
├─────────────────────────────────────────────────────────────┤
│ │
│ [本文] 00-overview — 运行时全景与学习路线图 │
│ ↓ │
│ 01-nodejs-runtime-internals — libuv、V8、Stream/Buffer │
│ ↓ │
│ 02-async-patterns-and-error-handling — 异步模式与错误处理 │
│ ↓ │
│ 03-express-deep-dive — Express 中间件与请求生命周期 │
│ ↓ │
│ 04-express-advanced-patterns — 认证、文件、API 版本化 │
│ ↓ │
│ 05-modern-node-frameworks — Fastify、Hono、NestJS 对比 │
│ ↓ │
│ 06-api-design-and-rest — RESTful API 设计原则 │
│ ↓ │
│ 07-environment-configuration — 配置管理与 12-Factor App │
│ │
└─────────────────────────────────────────────────────────────┘核心总结
总结1:Node.js 的本质
Node.js = V8(执行 JS)+ libuv(事件循环 + 异步 I/O)+ 绑定层。它不是"JS 版的多线程服务器",而是"在单线程上通过事件驱动实现高并发的异步 I/O 运行时"。理解这个本质,才能理解为什么 CPU 密集任务需要 Worker Threads,为什么阻塞事件循环会导致服务不可用。
总结2:框架选择的本质
框架不是越新越好,也不是越"企业级"越好。Express 的"简陋"在小型项目中是灵活性,在大型项目中是治理缺失。NestJS 的"臃肿"在小型项目是过度设计,在大型团队中是架构保障。选型要匹配团队规模、项目寿命和性能目标。
总结3:最重要的一个习惯
每个请求到达时,立即分配一个 requestId,注入到 logger 中,贯穿整个生命周期。 这是生产环境中排错效率从"小时级"降到"秒级"的关键。
章节测试
测试1:Node.js 的事件循环由哪个库实现?
A. V8 B. libuv C. OpenSSL D. npm
测试2:以下关于 Node.js Stream 的说法哪个是正确的?
A. Stream 总是比一次性读取更快 B. pipe() 不会处理背压(backpressure) C. Readable Stream 适合处理超大文件,避免内存溢出 D. Stream 只能用于文件操作
测试3:process.nextTick 和 setImmediate 的执行顺序是什么?
A. setImmediate 先于 process.nextTick B. process.nextTick 先于 setImmediate C. 取决于事件循环阶段 D. 它们是同一个东西的不同名称
测试4:以下哪个场景 Node.js 最不适合?
A. RESTful API 服务 B. WebSocket 实时通信 C. 视频转码服务(CPU 密集) D. BFF 聚合层
测试5:请简述 CJS 和 ESM 的互操作限制——为什么 CJS 不能用 require() 加载 ESM 模块?
测试6:Express 和 Fastify 的核心设计差异是什么?什么场景选 Express,什么场景选 Fastify?
参考答案
测试1答案
答案:B。libuv 是 Node.js 的跨平台异步 I/O 库,实现事件循环、线程池和异步文件/网络操作。V8 负责 JS 执行,OpenSSL 负责加密,npm 是包管理器。
测试2答案
答案:C。Stream 的主要价值是内存效率——逐块处理数据而非一次加载全部。pipe() 自动处理背压。Stream 可用于文件、网络、压缩、加密等多种场景。Stream 不一定比一次性读取快(小文件可能更慢)。
测试3答案
答案:B。process.nextTick 在事件循环每个阶段之间执行,优先级高于 microtasks。setImmediate 在 check 阶段执行。因此 process.nextTick 总是先于 setImmediate 执行。
测试4答案
答案:C。视频转码是典型的 CPU 密集任务,会长时间占用事件循环,阻塞其他请求处理。应使用 Worker Threads、独立转码服务或非 Node.js 的方案(如 FFmpeg 子进程)。
测试5答案
CJS 使用 require() 同步加载模块,而 ESM 规范要求 import 是异步的(支持静态分析和 tree-shaking)。require() 是同步函数,无法在同步上下文中处理异步的 ESM 加载。因此 CJS 模块必须使用 await import() 来加载 ESM 模块(动态导入返回 Promise)。
测试6答案
Express 核心是中间件链(洋葱模型),极简灵活,生态最丰富。Fastify 核心是 Schema 驱动的序列化/验证,插件系统高度封装,性能显著优于 Express。
选择 Express:快速原型、依赖大量社区中间件、团队已熟悉 Express、项目简单不需要强类型约束。 选择 Fastify:新项目注重性能、需要 Schema 自动生成 OpenAPI、团队重视 TypeScript 类型推导、需要插件封装的大型项目。
相关笔记
- [[01-nodejs-runtime-internals]] — libuv、V8、Stream/Buffer 深度覆盖
- [[03-express-deep-dive]] — Express 中间件洋葱模型与完整生命周期
- [[../01-javascript-and-typescript/03-async-and-event-loop]] — JS 事件循环基础
- [[../07-middleware/00-overview]] — 中间件生态(Redis、Kafka、ES)
下一步学习
- [ ] 阅读 Node.js 运行时内部原理 — 深入 libuv、V8 与核心抽象
- [ ] 阅读 Express 深度解析 — 掌握中间件洋葱模型
- [ ] 用 Express 写一个带 Zod 验证的 CRUD API,体会中间件链
- [ ] 用
clinic doctor分析一个 Node.js 服务的性能瓶颈
学习状态:🟡 开始学习