Skip to content

浏览器多进程架构与多线程模型

1. 浏览器的多进程架构

现代浏览器(如 Chrome)是多进程的。当你打开一个网页时,不仅仅是启动了一个进程,而是启动了多个进程协同工作。

主要进程

  1. Browser 进程(主进程)

    • 负责浏览器的“外壳”:地址栏、书签栏、前进后退按钮等。
    • 负责管理各个页面的协调、创建和销毁其他进程。
    • 网络资源的管理、下载等。
  2. Renderer 进程(渲染进程)

    • 核心进程。默认情况下,每个标签页(Tab)都有自己独立的渲染进程。
    • 负责将 HTML、CSS 和 JavaScript 转换为用户可交互的网页。
    • 出于安全考虑,运行在沙箱模式下。
  3. GPU 进程

    • 负责 3D 绘制和 CSS3 动画的硬件加速。
    • 多标签页共享一个 GPU 进程。
  4. Network 进程

    • 负责页面的网络资源加载(虽然在某些架构中整合在 Browser 进程中,但最新 Chrome 已独立)。
  5. Plugin 进程

    • 负责控制网页使用的插件(如 Flash,虽已淘汰,但架构上仍支持)。

为什么采用多进程?

  • 稳定性:一个插件崩溃或一个 Tab 崩溃不会导致整个浏览器崩溃。
  • 安全性:多进程架构配合沙箱机制,能有效隔离恶意代码。
  • 流畅性:JavaScript 的单线程执行不会阻塞浏览器主界面的响应。

2. 渲染进程中的多线程模型

渲染进程(Renderer Process)是前端开发者最关心的部分,所有的 HTML 解析、CSS 渲染、JS 执行都在这里完成。它包含多个线程。

核心线程

  1. GUI 渲染线程

    • 负责解析 HTML、CSS,构建 DOM 树和 RenderObject 树,布局和绘制等。
    • 互斥关系:GUI 渲染线程与 JS 引擎线程是互斥的。当 JS 引擎执行时,GUI 线程会被挂起,GUI 更新会被保存在队列中等到 JS 引擎空闲时立即被执行。
  2. JS 引擎线程

    • 也称为 JS 内核(如 V8 引擎)。
    • 负责处理 JavaScript 脚本程序(解析和执行)。
    • 单线程:一个渲染进程中无论什么时候,只有一个 JS 线程在运行 JS 程序。
    • 注意:如果 JS 执行时间过长,会阻塞 GUI 线程,导致页面渲染不连贯(卡顿)。
  3. 事件触发线程

    • 归属于浏览器(而非 JS 引擎),用来控制事件循环(Event Loop)。
    • 当 JS 引擎执行代码块如 setTimeout、鼠标点击、Ajax 请求时,会将对应的任务添加到事件线程中。
    • 当对应的事件符合触发条件被触发时,该线程会把事件添加到待处理队列的队尾,等待 JS 引擎的处理。
  4. 定时器触发线程

    • setIntervalsetTimeout 所在线程。
    • 浏览器定时计数器并不是由 JS 引擎计数的(因为 JS 是单线程的,如果阻塞了会影响计数的准确性)。
    • 计数完成后,将回调函数添加到事件队列中,等待 JS 引擎执行。
  5. 异步 HTTP 请求线程

    • 在 XMLHttpRequest 连接后通过浏览器新开一个线程请求。
    • 检测到状态变更时,如果设置有回调函数,异步线程就产生状态变更事件,将这个回调再放入事件队列中。

3. 常见问题解析

3.1 为什么 JS 是单线程的?

JavaScript 的主要用途是与用户互动以及操作 DOM。如果它是多线程的,会带来复杂的同步问题。

  • 假设线程 A 在 DOM 节点上添加内容,线程 B 删除了该节点,浏览器该以哪个为准?
  • 为了避免复杂性,JS 从诞生起就是单线程的。
  • 补充:HTML5 提出的 Web Worker 允许 JS 创建多个线程,但子线程完全受主线程控制,且不得操作 DOM,所以并未改变 JS 单线程的本质。

3.2 为什么 JS 会阻塞页面加载?

因为 GUI 渲染线程与 JS 引擎线程是互斥的。 当浏览器解析到 <script> 标签时,GUI 渲染线程会暂停,将控制权移交给 JS 引擎。JS 引擎执行完毕后,控制权才交还给 GUI 线程继续渲染。

  • 优化建议:将 <script> 放在 <body> 底部,或使用 defer / async 属性。

3.3 CSS 加载会阻塞 DOM 树解析吗?

  • 不会阻塞 DOM 树解析:HTML 解析器在遇到 <link> 标签下载 CSS 时,会继续解析后续的 DOM。
  • 会阻塞 Render 树渲染:渲染树的生成依赖 DOM 树和 CSSOM 树,如果 CSS 没加载完,页面无法渲染。
  • 会阻塞 JS 执行:因为 JS 可能会去获取元素的样式,如果 CSS 没下载完,JS 获取的样式可能是错的,所以浏览器会延迟 JS 的执行直到 CSS 下载解析完成。

3.4 Web Worker 是什么?

Web Worker 为 JavaScript 创造了多线程环境。

  • 允许主线程创建 Worker 线程,将一些计算密集型或高延迟的任务分配给 Worker 线程运行。
  • Worker 线程在后台运行,不会干扰用户界面(主线程)。
  • 限制:Worker 内无法操作 DOM,无法使用 window, document 等对象(可以使用 navigator, location 等部分属性)。

4. 总结图示

Browser 进程
  |
  +--- Network 进程 (下载资源)
  |
  +--- GPU 进程 (硬件加速)
  |
  +--- Renderer 进程 (每个Tab一个)
         |
         +--- GUI 渲染线程 (HTML/CSS) <----互斥----> JS 引擎线程 (V8)
         |                                           |
         +--- 事件触发线程 ------------------------->+ (Event Loop)
         |
         +--- 定时器触发线程
         |
         +--- 异步 HTTP 线程

MIT Licensed | Keep Learning.