Skip to content

Node.js 架构全景

Node.js 是基于 V8 引擎的 JavaScript 运行时,通过 libuv 实现非阻塞 I/O,适合构建高并发的网络应用。

架构组成

┌─────────────────────────────────────────────┐
│              Node.js Application             │
├─────────────────────────────────────────────┤
│           Node.js Core Modules               │
│    (fs, http, stream, crypto, path...)       │
├─────────────────────────────────────────────┤
│              Node.js Bindings                │
├──────────────────┬──────────────────────────┤
│    V8 Engine     │        libuv              │
│  (JS 执行引擎)    │  (事件循环 + 异步 I/O)    │
├──────────────────┴──────────────────────────┤
│              操作系统                         │
└─────────────────────────────────────────────┘

libuv 事件循环

Node.js 事件循环的 6 个阶段:

┌─────────────────────────────┐
│  1. timers                  │ ← setTimeout / setInterval 回调
│  2. pending callbacks       │ ← 上一轮延迟的 I/O 回调
│  3. idle, prepare           │ ← 内部使用
│  4. poll                    │ ← 获取新 I/O 事件(核心阶段)
│  5. check                   │ ← setImmediate 回调
│  6. close callbacks         │ ← socket.on('close') 等
└─────────────────────────────┘

每个阶段之间:清空 nextTick 队列 + 微任务队列

poll 阶段:
  - 如果有 I/O 回调 → 执行
  - 如果没有 → 等待新 I/O 事件(阻塞,直到有定时器到期)

模块系统

js
// CommonJS(Node.js 传统)
const fs = require('fs')
const { join } = require('path')
module.exports = { myFunction }

// ESM(现代,推荐)
import fs from 'fs'
import { join } from 'path'
export { myFunction }
export default class MyClass {}

// package.json 配置
{
  "type": "module"  // 启用 ESM
}

// 条件导出(同时支持 CJS 和 ESM)
{
  "exports": {
    ".": {
      "import": "./dist/index.mjs",
      "require": "./dist/index.cjs"
    }
  }
}

核心模块速览

js
import fs from 'fs/promises'
import path from 'path'
import { createServer } from 'http'
import { EventEmitter } from 'events'
import { Worker } from 'worker_threads'
import { createReadStream, createWriteStream } from 'fs'
import { pipeline } from 'stream/promises'
import crypto from 'crypto'
import os from 'os'

// fs/promises:文件操作
const content = await fs.readFile('file.txt', 'utf-8')
await fs.writeFile('output.txt', content)
const files = await fs.readdir('./src')
const stat = await fs.stat('file.txt')

// path:路径处理
const fullPath = path.join(__dirname, 'src', 'index.ts')
const ext = path.extname('file.ts')  // '.ts'
const dir = path.dirname('/foo/bar/baz.js')  // '/foo/bar'
const { name, ext: extension } = path.parse('file.ts')

// crypto:加密
const hash = crypto.createHash('sha256').update('data').digest('hex')
const salt = crypto.randomBytes(16).toString('hex')

// os:系统信息
const cpuCount = os.cpus().length
const totalMem = os.totalmem()
const freeMem = os.freemem()

Stream 流处理

js
import { pipeline } from 'stream/promises'
import { createReadStream, createWriteStream } from 'fs'
import { createGzip } from 'zlib'
import { Transform } from 'stream'

// 管道:读取 → 压缩 → 写入(内存高效)
await pipeline(
  createReadStream('input.txt'),
  createGzip(),
  createWriteStream('output.txt.gz')
)

// 自定义 Transform 流
const upperCase = new Transform({
  transform(chunk, encoding, callback) {
    callback(null, chunk.toString().toUpperCase())
  }
})

// 处理大文件(逐行读取)
import readline from 'readline'

const rl = readline.createInterface({
  input: createReadStream('large-file.csv'),
  crlfDelay: Infinity
})

for await (const line of rl) {
  processLine(line)  // 逐行处理,不占用大量内存
}

Worker Threads(CPU 密集型任务)

js
// main.js
import { Worker, isMainThread, parentPort, workerData } from 'worker_threads'

if (isMainThread) {
  // 主线程:创建 Worker
  function runWorker(data) {
    return new Promise((resolve, reject) => {
      const worker = new Worker(new URL(import.meta.url), {
        workerData: data
      })
      worker.on('message', resolve)
      worker.on('error', reject)
    })
  }

  // 并行执行 CPU 密集型任务
  const results = await Promise.all([
    runWorker({ start: 0, end: 1000000 }),
    runWorker({ start: 1000000, end: 2000000 }),
    runWorker({ start: 2000000, end: 3000000 }),
    runWorker({ start: 3000000, end: 4000000 }),
  ])

  console.log('总和:', results.reduce((a, b) => a + b, 0))
} else {
  // Worker 线程:执行计算
  const { start, end } = workerData
  let sum = 0
  for (let i = start; i < end; i++) sum += i
  parentPort.postMessage(sum)
}

性能最佳实践

js
// 1. 避免阻塞事件循环
// ❌ 同步读取大文件
const data = fs.readFileSync('large-file.txt')

// ✅ 异步读取
const data = await fs.readFile('large-file.txt')

// 2. 连接池(数据库)
import { Pool } from 'pg'
const pool = new Pool({ max: 20 })  // 复用连接,不要每次请求都创建新连接

// 3. 内存泄漏检测
process.on('warning', (warning) => {
  if (warning.name === 'MaxListenersExceededWarning') {
    console.error('可能存在内存泄漏:', warning)
  }
})

// 4. 优雅关闭
process.on('SIGTERM', async () => {
  console.log('收到 SIGTERM,开始优雅关闭...')
  await server.close()
  await db.end()
  process.exit(0)
})

总结

  • Node.js 单线程 + 非阻塞 I/O,适合 I/O 密集型,不适合 CPU 密集型
  • CPU 密集型任务用 Worker Threads 或子进程
  • Stream 处理大文件,避免一次性加载到内存
  • 生产环境用 PM2 或 Docker 管理进程,配置优雅关闭

系统学习 Web 前端生态,深入底层架构