浏览器揭秘

浏览器结构

浏览器主要组件有 7 个,用户界面浏览器引擎渲染引擎网络用户界面 后端JS 解析器数据存储

浏览器主要组件

  • 用户界面: 除了浏览器主窗口显示请求的页面外,其他显示的各部分都属于用户界面,如地址栏,状态栏,工具栏等
  • 浏览器引擎在用户界面渲染引擎之间传送指令
  • 渲染引擎: 负责显示所请求的内容。解析 HTML 和 CSS,并将解析后的内容显示在屏幕
  • 网络:用于网络调用,例如 HTTP 请求
  • JS 解析器:用于解析和执行 JavaScript 代码
  • 数据存储:持久层,浏览器需要在硬盘保持各种数据,例如 Cookie。浏览器还支持存储机制,如LocalStorage,IndexedDB,WebSQL

渲染引擎(Rendering engine)

不同浏览器使用不同的渲染引擎

  • Blink: Chrome, Opera
  • Webkit: Safari
  • Gecko: Firefox
  • Trident: Internet Explorer
  • EdgeHTML: Edge
  • Presto: Opera(遗留)

Rendering Engines & JavaScript Engines

渲染流程

渲染引擎一开始会从网络层获取请求文档的内容,内容大小一般限制在 8kb 的块以内。
然后进行如下基本流程:
rendering engine basic flow

  1. 解析 HTML 文档,并将元素转为内容树(content tree)中的 DOM 节点;
  2. 解析 css 样式,样式消息和 HTML 中的可视化指令一起创建了渲染树(redner tree)
  3. 渲染树包含带有颜色和尺寸等视觉属性的矩形,这些矩形会按其排列的顺序在屏幕上显示
  4. 渲染树构建完成之后,进入布局阶段,也就是为每一个节点分配一个它应该出现在屏幕上的确切坐标
  5. 绘制阶段,渲染引擎会遍历渲染树,并由用户界面后端层将每个节点绘制处理

注意: 这是一个渐进的过程。为了获得更好的用户体验,渲染引擎将会尽快在屏幕显示内容。它不会等到所有 HTML 都被解析后才开始构建渲染树、设置布局。在不断接受和处理来自网络的其余内容的同时,渲染引擎会将部分内容解析并显示。
render main flow

解析/DOM 树构建

树包含 DOM 节点,指的是树是由实现了某个 DOM 接口的元素构成的

解析

解析文档是指将文档转化成为有意义的,可以让代码理解、使用的结构。解析得到的结构通常代表了文档结构的节点树,它被称之为解析树/语法树。

  • HTML 解析:将 HTML 标记解析成解析树。解析树是由 DOM 元素和属性节点构成的树结构。DOM(文档对象模型),是 HTML 文档的对象表示,同时也是外部内容与 HTML 元素之间的接口
  • CSS 解析: 将 CSS 文件解析成 StyleSheet 对象,且每个对象都包含 CSS 规则。CSS 规则对象则包含选择器和声明对象。
    parse CSS

脚本顺序

解析器遇到<script>标记时立即解析并执行脚本,文档的解析将停止,直到脚本执行完毕。如果脚本是外部的,解析过程会停止,直到从网络同步获取资源完成后再执行。脚本标注为defer,它不会停止文档解析,而是等到解析结束才执行;脚本标注为async,它表示异步,由其它线程解析和执行,文档解析不受影响
脚本解析、执行顺序

渲染树构建

在 DOM 树构建的同时,浏览器还会构建另一个树结构,渲染树,它是由可视化元素按照其显示顺序而组成的树,即文档的可视化表示。其目的是使让内容按照正确的顺序绘制。
webkit 将渲染树中的元素成为渲染对象/渲染器,它知道如何布局并将自身及其子元素绘制出来。RenderObject 类使所有渲染对象的基类,其定义如下:

1
2
3
4
5
6
7
8
9
calss RenderObject {
virtual void layout();
virtual void paint(PaintInfo);
virtula void rect repaintRect();

Node* node; // DOM 节点
RenderStyle* style; // 计算样式
RenderLayer* containgLayer; // the containing z-index layer
}
  • 每个渲染对象都代表一个矩形区域,通常对应于相关节点的 CSS 框

渲染树和 DOM 树的关系

  • 渲染对象和 DOM 元素相对应,但并非一一对应,非可视化的 DOM 元素不会插入 DOM 树,如<head>元素,如果元素的样式display:none;,该元素也不在渲染树中。但visibility:hidden;的元素仍会显示。
  • 有些 DOM 元素对应多个可视化对象,它们往往具有复杂结构的元素,无法用单一的矩形来描述。例如,<select>元素有 3 个渲染对象,显示区域,下拉列表框,按钮。
  • 有些渲染对象对应于 DOM 节点,但在树中的位置与 DOM 节点不同。浮动定位绝对定位的元素,处于正常的流程之外,放置在树中的其他地方,而放置在原位的使占位对象

构建渲染树的流程

处理<html>,<body>标记会构建渲染树的根节点。这个根节点渲染对象对应于 CSS 最上层的容器 block,且包含了其他所有的 block。它的尺寸就是视口,即浏览器窗口显示区域的尺寸。渲染树的其余部分以 DOM 树节点插入的形式来构建。

  • 构建渲染树时,需要计算每一个渲染对象的可视化属性,这是通过计算每个元素的样式属性来完成的,

布局

渲染对象在创建完成并添加到渲染树时,并不包含位置和大小信息。计算这些值的过程称为布局或重排。

Dirty 位系统

为了避免对所有细小的更改都进行整体布局,浏览器采用了一种弄”dirty 位”的系统。如果某个渲染对象发生了更改,或将自身或其子代标记为”dirty”,表示需要进行布局

全局布局和增量布局

  • 全局布局(往往是同步触发的)指触发了整个渲染树范围的布局,触发原因可能包括:
      1. 影响所有渲染对象的全局更改,如字体大小
      1. 屏幕大小调整
  • 当渲染对象为 dirty 时,会异步触发增量布局。浏览器会将“reflow 命令”加入队列,而调度程序 会触发这些命令的批量执行。
  • 请求样式信息的脚本可同步触发增量布局

绘制

在绘制阶段,系统会遍历渲染树,并调用渲染对象的”paint”方法,将渲染对象绘制在屏幕上。绘制工作用户界面基础组件完成的。

绘制顺序

CSS2 规范定义了绘制流程的顺序,即按照属性z-index来决定绘制顺序

  • 根元素具有根层叠上下文
  • z-index 不为”auto”的定位元素,就创建了一个新的层叠上下文(Stacking Context)
  • 定位元素以及父元素为 flex 定位的元素,必须依赖 z-index 值才能创建层叠上下位,所以统称为依赖 z-index 的层叠上下文元素。而其他属性即不依赖 z-index 的层叠上下文。
  • 一个层叠上下文有 7 中层叠等级,由低到高:
      1. 背景和边框: 层叠上下文的元素的背景和边框
      1. 负 z-index 值:层叠上下文内负 z-index 值的子元素
      1. 块级盒: 文档流中非行内非定位的子元素
      1. 浮动盒: 非定位的浮动元素
      1. 行内盒:文档流中行内非定位子元素
      1. z-index:0
      1. 正 z-index 的值
        z-index order