浏览器整体架构:多进程多线程
现代浏览器(以Chrome为代表)采用分层、多进程的架构,主要目的是安全、稳定和性能。一个典型的浏览器可以被抽象为下图所示的三层结构:
- 第一层:用户界面 :我们看到的地址栏、书签栏、按钮等。它运行在独立的 浏览器进程 中,响应用户的全局操作。
- 第二层:浏览器内核 :浏览器的"大脑",负责调度和管理。网络线程 处理请求,UI后端线程 绘制基础控件,而最核心的渲染引擎 (如Blink)和JS引擎 (如V8)则运行在独立的渲染进程中。
- 第三层:数据持久层:负责Cookie、本地存储、缓存等数据的读写。

主要进程及其职责包括:
| 进程 | 职责 |
|---|---|
| 浏览器进程 | 负责界面显示(地址栏、书签)、用户交互、子进程管理等。 |
| GPU进程 | 负责独立的图形绘制(3D CSS、WebGL)。 |
| 网络进程 | 负责所有网络资源加载。 |
| 渲染进程(核心) | 每个标签页通常对应一个独立的渲染进程,负责解析HTML/CSS、执行JavaScript、进行布局和绘制(排版、渲染)。我们说的"主线程"就在这里。 |
| 插件进程 | 每个插件独立进程,防止崩溃影响浏览器。 |
所以,浏览器整体是多进程的。而在一个渲染进程内部,又包含多个线程协同工作
🧵 渲染进程内的线程分工
一个典型的渲染进程包含以下关键线程:
- GUI渲染线程 :负责解析HTML/CSS、构建DOM树、CSSOM树、布局和绘制等。注意:GUI渲染线程与JS引擎线程是互斥的。
- JavaScript引擎线程(这就是我们常说的"主线程"或"UI线程") :负责执行JavaScript代码(如V8引擎)。我们常说的"JavaScript是单线程的",指的就是这个线程。
- 定时器触发线程 :管理
setTimeout、setInterval的计时,计时完毕将回调加入任务队列。 - 异步HTTP请求线程 :处理
XMLHttpRequest、fetch等网络请求,完成后将回调加入任务队列。 - 事件触发线程:管理事件循环,当事件(如点击)触发时,将对应的回调函数加入任务队列。
- 合成线程:将页面分层信息发送给GPU进程。
核心:"主线程"是什么?
我们通常所说的 "主线程" ,狭义上指 "JavaScript引擎线程" ,广义上指的是承担了JavaScript执行、页面渲染(GUI)、事件处理等核心工作的这个单一线程执行模型。
因为GUI渲染线程 和JS引擎线程是互斥的,它们不能同时执行,所以可以理解为一个"工作主线程"在不同时段切换着做这两件事。其工作流程可以总结为下图:

为什么这样设计? 主要是为了保证DOM操作结果的一致性。如果JS线程和渲染线程同时工作,JS可能在渲染中途修改DOM,导致渲染出错。互斥执行简化了并发控制,但带来了性能挑战。
🧵 微观机制:渲染进程与事件循环
作为前端开发者,我们必须深入理解渲染进程的内部,因为我们的代码就在这里执行。下图描绘了渲染进程中,从接收网络数据到最终屏幕像素的关键工作流:

结合上图,我们来理解几个最关键的概念:
-
渲染流水线
这是浏览器将代码变成像素的过程。你需要理解几个关键步骤:
- 解析与构建树 :HTML解析为DOM树 ,CSS解析为CSSOM树。
- 布局:计算每个DOM元素在视口中的精确位置和大小(又称"回流")。
- 绘制 :将元素的文本、颜色、边框等视觉信息填充到多个图层上(又称"重绘")。
- 合成 :这是现代浏览器保持流畅的关键。合成线程 将各个图层分块,交由GPU进程 进行光栅化(变成位图),最后像叠盘子一样合成为最终画面。这个过程完全在独立的线程进行,不阻塞主线程。
-
事件循环:JavaScript的并发模型
是 JavaScript 实现异步编程的核心机制,其作用是协调同步任务 、异步任务的执行顺序,让单线程的 JS 能够高效处理非阻塞操作(如网络请求、定时器、DOM 事件)。
-
宏任务队列 :包含
setTimeout、setInterval、I/O、UI渲染、MessageChannel等回调。 -
微任务队列 :包含
Promise.then、MutationObserver、queueMicrotask等回调。
运行规则 :每执行一个 宏任务后,会清空整个微任务队列,然后检查是否需要渲染,接着再取下一个宏任务。
核心规则 :一个宏任务 → 所有微任务 → (可能渲染)→ 下一个宏任务。
-
💡 对前端开发的深刻启示
-
性能瓶颈在主线程 :所有同步JS、DOM操作、样式计算、布局都发生在同一个主线程上。这就是为什么长时间的同步JS会"卡死"页面------它阻塞了渲染和事件处理。
-
理解渲染时机 :浏览器会智能地合并多次DOM操作,但直接读取某些布局属性(如
offsetTop、getComputedStyle)会强制触发同步布局,导致性能骤降。 -
善用异步与分层:
- 用
requestAnimationFrame执行动画,让它与渲染周期对齐。 - 将耗时计算移入 Web Worker(运行在独立线程,无法访问DOM)。
- 利用CSS
transform和opacity属性进行动画,它们可以由合成线程单独处理,完全避开主线程和重绘,效率最高。
- 用
-
React调度器的用武之地 :React正是深刻理解了上述机制,才用
MessageChannel将渲染工作拆分为5ms左右的可中断任务单元。每个单元执行后,通过事件循环将控制权交还浏览器,从而避免长任务阻塞,实现流畅的并发更新。