Node.js 工作机制

V8、libuv、事件循环三者怎么配合跑完一次异步调用。

Intermediate
Key PointsV8 执行 JS,libuv 负责 I/O 与事件循环,回调最终回到主线程排队执行。

三层结构

LayerJob
Node 标准库(JS)fs、http、net 等,对下层做封装
V8把 JS 编译成机器码并执行
libuv事件循环、线程池、跨平台异步 I/O

一次 readFile 的全过程

  1. JS 调用 fs.readFile,进入 C++ 绑定层
  2. libuv 把任务丢进线程池(默认 4 个线程)
  3. 主线程立刻返回,继续执行后面的 JS
  4. 线程池读完文件,把结果放进完成队列
  5. 事件循环在 poll 阶段取出回调,交给 V8 执行
JavaScript
const fs = require('node:fs');

console.log('1 开始');

fs.readFile(__filename, () => {
  console.log('3 回调');
});

setTimeout(() => console.log('2 定时器'), 0);

console.log('4 同步结束');
Output
1 开始
4 同步结束
2 定时器
3 回调

The order shows three things: sync code runs first; setTimeout callbacks fire in the timers phase; file I/O callbacks wait for the thread pool and usually land after timers.

线程池大小

Bash
# 默认 4,可调
UV_THREADPOOL_SIZE=8 node app.js

The pool serves **filesystem, dns.lookup, crypto pbkdf2/scrypt and zlib** work. Network sockets do not use the pool — they use epoll/kqueue notifications, so HTTP servers are not limited by those 4 threads.

crypto.pbkdf2 is common in login endpoints. With 4 threads, 8 concurrent logins leave 4 queued on hashing — visible as "slow login at peak". Raise UV_THREADPOOL_SIZE or switch to async WebCrypto.

Friends & Partners