# 浏览器的渲染原理

其实,这个题目用来回答这道经典面试题《在浏览器里,从输入URL到页面展示,这中间发生了什么?》也是一样的。

# 浏览器的进程

首先,先简单说下浏览器的进程。以chrome为例,是多进程模型,一般有以下几个进程:

  1. 浏览器进程。主要负责用户交互、子进程管理和文件存储等功能。
    • UI线程。控制浏览器上的按钮及输入框
    • 存储线程。控制文件等的访问
  2. 渲染进程。主要负责把htmljscss、图片等资源解析为可以显示和交互的页面。运行在安全沙箱里,为了保障系统的安全。
    • JavaScript引擎线程。与GUI线程互斥。
    • GUI 渲染线程
    • 定时触发器线程
    • 事件触发线程
    • 异步http请求线程
    • 一个合成器线程
    • 多个光栅化线程
  3. GPU进程。
  4. 插件进程。
  5. 网络进程。面向渲染进程、浏览器进程提供网络下载功能。

多进程

优点:提升了浏览器的稳定性、流畅性和安全性。

  1. 更高的容错性
  2. 更高的安全性和沙盒性(sanboxing)
  3. 更高的响应速度

缺点是:资源占用大,体系架构复杂

# 请求步骤

可以分成以下几个步骤:

# 浏览器进程接收到用户输入的URL

  1. 判断是否搜索内容。如果是使用搜索引擎,合成新的URL。
  2. 如果当前正处于某页面,让当前页执行beforeunload事件的退出操作。
  3. 浏览器进程把URL转发给网络进程。

# 网络进程中发起真正的URL请求

  1. 判断是否有缓存。有的话,直接返回资源给浏览器进程。
  2. 进行DNS域名解析。如果是https,还得建立TLS连接。
  3. TCP连接。三次握手,向服务器发送构建的请示信息。如果是http1.1协议,一个站点会开启6个连接,如果是http2.0,只会发起一个。
  4. 服务器生成响应数据,再发送给网络进程
  5. 网络进程接收到响应头数据。
    • 判断状态码。如果需要重定向,则根据返回的location字段跳转,重新发起请求。
    • 判断响应数据类型。如果是字节流,进行下载,本次导航结束。
    • 解析数据,转发给浏览器进程。

# 准备渲染进程

检查是否同一站点。相同的协议和根域名,就被认为是同一站点。

如果是,则复用一个进程。否则,会新开一个进程。

当然,这只是chrome的默认策略,也可以进行修改。此处不再赘述。

# 提交文档

  1. 浏览器进程收到网络进程的响应头数据后,向渲染进程发起提交文档的消息
  2. 渲染进程和网络进程建立传输数据的管道
  3. 等文档数据传输完成后,渲染进程返回确认提交的消息给浏览器进程。这是告诉浏览器进程:已经准备好接收和解析页面数据了。
  4. 浏览器进程更新浏览器界面状态。
    • 安全状态
    • 地址栏的url
    • 前进后退的历史状态
    • 更新web页面

# 渲染阶段

  1. 构建DOM树DOM 树是由 DOM 元素及属性节点组成的。
  2. 样式计算。
    • 把css转换为浏览器所能理解的结构(styleSheets
    • 转换样式表中的属性值,使其标准化
    • 计算出DOM树中每个节点的具体样式
  3. 布局阶段。
    • 创建布局树。添加可见节点,忽略不可见节点。
    • 布局计算。
  4. 分层阶段。
    • 拥有层叠上下文属性的元素会被提升为单独一层
    • 需要裁剪的地方也会被创建为图层
  5. 绘制阶段。
    • 提供一个有绘制指令的绘制列表。
  6. 光栅化
    • 主线程把绘制列表提交给合成线程
    • 合成线程按照视口附近的图块优先生成位图
      • 合成线程把图层划分为图块
      • 实际生成位图的操作是由栅格化来执行的
      • 所谓栅格化,就是指将图块转换为位图
      • 使用GPU生成位图的过程叫快速栅格化,生成的位图保存在GPU内存
  7. 合成与显示
    • 合成线程生成一个绘制图块的命令
    • 提交命令给浏览器进程
    • 浏览器进程绘制页面内容到内存
    • 将内存显示到屏幕

注:本文主要参考李兵老师的《浏览器工作原理与实践 (opens new window)》,严重推荐。