Node.js 运行时架构

解释 Node.js 如何由 V8、Node API、C++ bindings、libuv 与操作系统协作,形成单主线程事件循环模型。

#type / concept #status / growing #tech / dev / backend #resource / nodejs #resource / javascript

[!info] related notes

Node.js 运行时架构

一句话定义

Node.js 的运行时架构可以概括成:

JavaScript 代码由 V8 执行,异步 I/O 和事件循环主要由 libuv 调度,Node 再通过宿主 API 把文件、网络、进程和流式能力暴露给业务代码。

核心机制 / 工作原理

可以把它看成四层:

JavaScript 业务代码

Node.js API:fs / http / net / stream / crypto / process

V8 + C++ bindings + libuv

操作系统:文件、网络、进程、线程、时钟

1. V8 负责什么

  • 执行 JavaScript 代码
  • 管理对象、闭包、作用域和 GC
  • 把你的业务逻辑跑在主线程调用栈里

如果要把引擎本身单独看清,可以继续读 V8

2. Node.js API 负责什么

  • 暴露服务端常用能力
  • 把 JavaScript 层的调用桥接到底层实现
  • 提供统一编程模型,例如 fshttpBufferStream

3. libuv 负责什么

  • 事件循环
  • 定时器调度
  • 一部分异步 I/O 协调
  • 线程池任务分发

它也是为什么 Node.js 能把很多 I/O 型等待从主线程里拿走。

如果要继续细看 poll、worker pool 和 handle/request 生命周期,看 libuvlibuv 事件循环与 Worker Pool

4. 操作系统负责什么

  • 文件读写
  • 网络连接
  • 进程与线程
  • 时钟与信号

Node.js 不是自己“发明”了异步 I/O,而是把操作系统能力封装成更适合 JavaScript 的宿主模型。

最小例子 / 最小场景

当你写出这样一段代码:

import { readFile } from 'node:fs/promises';

const content = await readFile('./a.txt', 'utf8');
console.log(content);

大致发生的是:

  1. JavaScript 代码在 V8 主线程里运行
  2. readFile 通过 Node API 进入底层
  3. 底层把文件读取交给 libuv / 操作系统
  4. 主线程先继续空出来处理别的任务
  5. 文件读取完成后,再把后续逻辑调回事件循环继续执行

边界与易混淆点

Node.js 是单线程的吗

更准确的说法是:

  • JavaScript 业务执行主线程通常是单线程
  • 但 Node.js 整体不是“只有一个线程”
  • libuv 有线程池
  • V8 也有后台线程

所以它更接近:

单主线程事件循环模型,而不是“整个运行时只有一条线程”。

为什么适合 I/O 密集型

因为大量等待数据库、网络、文件返回的时间,不需要一直卡住主线程。

为什么不适合 CPU 密集型

因为你的 JavaScript 计算本身还是跑在主线程里。只要计算持续太久,整个事件循环就会被堵住。

创建于 2026/5/21 更新于 2026/5/27