一.核心结论速记
一句话概括 Node.js 架构:
单线程主线程负责接活、派活、跑回调,多线程 libuv 线程池负责干慢活累活,主线程全程不阻塞。
二.分层拆解

1. 第一层:你的应用代码(Application)
就是你写的 .js 文件,比如 fs.readFile、http.createServer 这类业务代码。
- 作用:定义业务逻辑,发起各种操作请求(同步/异步)。
- 关系:所有代码最终都会交给 V8 引擎执行。
2. 第二层:V8 引擎(JavaScript 引擎)
- 它是 Google 开发的 JS 引擎,Node.js 用它来执行 JS 代码。
- 核心特点:单线程执行,同一时间只能处理一件事。
- 打比方:就像餐厅里唯一的大厨,同一时间只能炒一道菜。
3. 第三层:Node.js Bindings(Node API 绑定层)
- 它是「翻译官+联络员」,连接 V8 和底层系统/libuv。
- 作用:
-
- 把 JS 调用(比如
fs.readFile)翻译成操作系统能懂的指令。 - 把耗时的 I/O 操作,交给 libuv 处理,不让 V8 阻塞。
- 把 JS 调用(比如
- 打比方:餐厅的传菜员,把顾客的点单传给后厨,再把做好的菜端给大厨/顾客。
4. 第四层:libuv(异步 I/O 核心)
这是 Node.js 实现异步非阻塞的关键,包含两大核心组件:
① 事件循环(Event Loop)
- 运行在主线程,和 V8 共用同一个线程。
- 核心作用:循环检查「待办事项」,保证主线程不空闲。
- 它会按顺序检查:
-
- 有没有新的同步代码要执行?
- 异步操作的结果有没有返回?(比如文件读完了、网络请求完成了)
- 把就绪的回调函数拿出来,交给 V8 执行。
- 打比方:大厨的"耳朵和眼睛",炒完一道菜,就听有没有帮工喊"菜做好了",然后继续处理下一个任务。
② 线程池(Worker Threads)
- 专门处理阻塞/耗时任务 的多线程池,默认 4 个线程(可通过
UV_THREADPOOL_SIZE调整)。 - 哪些任务会交给它?
-
- 文件系统操作(fs.readFile、fs.writeFile 等)
- 加密解密(crypto 模块)
- 数据压缩(zlib 模块)
- DNS 解析(dns.lookup)
- 处理流程:主线程把慢活扔给线程池,线程池并行处理,干完后把结果和回调函数扔回事件队列,由主线程执行回调。
- 打比方:餐厅的后厨帮工,负责洗菜、切肉、煮汤这些慢活,多个人一起干,不耽误大厨炒菜。
补充:网络 I/O 不走线程池
- 像
http、tcp、websocket这类网络请求,libuv 会用操作系统的「多路复用」技术(epoll/kqueue/IOCP)处理。 - 全程在主线程处理,不依赖线程池,所以 Node.js 天生适合高并发网络服务。
三.完整流程串讲
看这段代码:
js
console.log('点餐开始');
fs.readFile('./big-file.txt', () => {
console.log('文件读完了!上菜');
});
console.log('点完别的菜了');
- 同步代码执行阶段
-
- 主线程(V8)先执行
console.log('点餐开始'),打印这句话。 - 遇到
fs.readFile,知道这是慢活,通过 Bindings 交给 libuv 线程池处理,主线程继续往下走。 - 主线程接着执行
console.log('点完别的菜了'),打印这句话。
- 主线程(V8)先执行
- 线程池干活阶段
-
- 线程池里的帮工开始读文件,主线程这边完全不卡,继续处理其他请求。
- 回调执行阶段
-
- 帮工读完文件,把结果和回调函数扔到事件队列里。
- 主线程把所有同步代码都执行完后,事件循环开始检查队列,发现有就绪的回调,就拿过来执行,打印
文件读完了!上菜。
四.关键误区澄清
| 误区 | 正确理解 |
|---|---|
| Node.js 是多线程的 | 主线程(V8+事件循环)是单线程,只有线程池是多线程的 |
| 所有异步操作都走线程池 | 网络 I/O 不走线程池,只有文件、加密等阻塞任务才走 |
| 线程池越多,性能越好 | 线程池过大会导致线程切换开销增加,默认 4 个已能满足大部分场景 |
五.问题解读
如果是Node向其他服务器发送请求会经过LIBUV吗?
会经过LIBUV,但是不经过线程池,因为LIBUV通过多路复用,所有的网络请求都是单线程处理,只有文件 / 加密 / DNS 才走 LIBUV 线程池。
j's
你的 JS 代码
↓
V8 引擎
↓
Node Bindings
↓
【 libuv 】← 网络请求全在这里处理!
↓
操作系统
| 方式 | 谁发的 | 走谁的网络 | 走 libuv 吗 |
|---|---|---|---|
| Vue axios | 浏览器 | 浏览器内核 | ❌ 不走 |
| Node http/axios | Node 服务 | Node 内核 | ✅ 一定走 |
| 文件读写 | Node | Node | ✅ 走 libuv 线程池 |
| 网络请求 | Node | Node | ✅ 走 libuv 多路复用 |
💡提示:不管是 Node 接收请求,还是 Node 发送请求,全都走 libuv!而且全都不走线程池,全是主线程 + 多路复用!
六.一句话终极总结
主线程单线程接活、派活、跑回调,libuv 线程池多线程干慢活,主线程全程不阻塞,这就是 Node.js 高性能的核心秘密。