1. 宏观进程架构
浏览器(以 Chrome 为例)—— 多进程架构
- Browser 进程(主进程):负责地址栏、书签、前进/后退,以及网络请求、文件访问等特权操作
- Renderer 进程:每个 Tab(或同站点组)一个,负责页面渲染、JS 执行、DOM 操作。出于安全考虑运行在沙箱中
- GPU 进程:统一处理合成、绘制
- Plugin 进程:运行浏览器插件
- Utility 进程:网络服务、音视频解码等
Node.js —— 单进程、单主线程模型
- 一个主线程运行 JS(V8 引擎)
- 通过 libuv 线程池处理文件 I/O、DNS 查询等阻塞操作
- 可通过
worker_threads创建工作线程,或child_process/cluster创建子进程
2. 共同的核心:V8 引擎
无论是浏览器还是 Node.js,JS 代码的解析、编译、执行都依赖 V8 引擎。V8 负责的事情是纯粹的:
- 将 JS 源码解析为 AST
- 通过 Ignition 解释器生成字节码
- 通过 TurboFan 将热点代码优化编译为机器码
- 管理堆内存、垃圾回收(GC)
V8 本身不提供任何 I/O 能力——它不知道什么是 DOM、什么是文件系统、什么是网络请求。这些能力由宿主环境注入。
3. 宿主环境的差异
| 能力 | 浏览器 | Node.js |
|---|---|---|
| DOM / BOM | document, window, navigator | 无 |
| 文件系统 | 无(有限的 File API) | fs, path 等模块 |
| 网络 | fetch, XMLHttpRequest | http, net, dgram 等模块 |
| 进程/线程 | Web Workers | child_process, worker_threads |
| 事件循环实现 | 浏览器内核实现(与渲染管线交织) | libuv 实现 |
| 模块系统 | ES Modules(原生) | CommonJS + ES Modules |
| 全局对象 | window / globalThis | global / globalThis |
4. 浏览器中 JS 的执行模型
浏览器中的 Renderer 进程,核心就是两件事的协作:页面渲染 和 事件循环。
- 页面渲染:HTML 解析 -> DOM 树 + CSSOM -> Layout -> Paint -> Composite。JS 可以在任意阶段介入修改 DOM/CSSOM,触发重排(reflow)或重绘(repaint)。
- 事件循环:JS 的主线程通过事件循环调度任务。一轮循环大致为:
- 从宏任务队列(macrotask)取一个任务执行(如
setTimeout回调、用户事件) - 清空微任务队列(microtask)(如
Promise.then、MutationObserver) - 如果需要,执行渲染更新(requestAnimationFrame -> Style -> Layout -> Paint)
- 回到第 1 步
- 从宏任务队列(macrotask)取一个任务执行(如
关键点在于:JS 执行和页面渲染共享同一个主线程,所以长时间的 JS 运算会阻塞渲染,造成页面卡顿。
总结
V8 是 JS 的"发动机",浏览器和 Node.js 是不同的"车身"——发动机相同,但车身提供的能力(DOM vs 文件系统)、调度方式(浏览器事件循环 vs libuv 事件循环)各不相同。