HTML/CSS/JS
浏览器接收 这三种文件,渲染出页面
HTML:HyperText Marked Language, 超文本标记语言, 标记 和 文本 组成
CSS: Cascading Style Sheets, 层叠样式表, 选择器 和 属性组成
JS: Javascript, 解释型编程语言, 能让页面’动’起来
渲染流水线分为以下8个子阶段:
构建DOM树 样式计算 布局阶段 分层 绘制 分块 光栅化 合成
构建DOM树
创建出节点
1.HTML被转换为浏览器能理解的结构,DOM树
根据HTML中的 层次结构,将HTML解析为 具有父子节点关系的DOM树
浏览器输入document可以看到DOM树结构
样式计算
计算出每个节点的样式
2.将CSS转换为浏览器能理解的结构,styleSheets
CSS三个来源link外部CSS文件,style标签内的CSS,元素style属性内的CSS
该结构具备查询和修改功能
浏览器输入document.styleSheets查看
3.转换样式表中的属性值,使其标准化
如:2em,blue,bold等属性值
4.计算出DOM树中每个节点的具体样式(继承和层叠)
继承:子节点继承父节点样式,层叠:一个DOM节点合并多个来源属性值的优先级
布局阶段
计算出DOM树中 可见元素 的 几何位置
5.创建布局树
构建只含可见元素的布局树,如 head标签下的全部内容全不可见
6.布局计算
进行布局操作的时候,会把布局运算的结构又写回布局树
所以布局树既是输入又是输出,这是布局阶段一个不合理的地方
Chrome团队正在重构代码,下一代布局系统叫LayoutNG,试图清晰分离输入输出,布局算法更加简单
分层
渲染引擎为特定节点生成专用图层,并生成图层树(layerTree)
一个图层可包含多个节点,满足以下情况之一会生成图层
拥有层叠上下文属性的元素会单独一层(position:fixed,z-index,opacity:0.5)
被裁剪过的元素,如 div盒子长宽小于内容长宽绘制列表 为每个图层生成绘制列表,交给合成线程
渲染引擎将一个图层的绘制分成多个绘制指令,组成待绘制列表
绘制列表 只是用来记录 绘制顺序 和 绘制指令 的列表,
光栅化
主线程将绘制列表提交给合成线程,实际绘制由 渲染引擎 中的 合成线程 来完成
视口(viewport):用户能看见的页面部分,
图块(tile):栅格化的最小单位,256X256或512X512,合成线程 将图层分化而来
栅格化/光栅化: 将 图块 转化为 位图
快速栅格化/GPU栅格化: 栅格化在专门的 栅格化线程池 中执行, 通常使用GPU生成位图,
结果的位图数据 在GPU内存中,这就涉及了跨进程操作,渲染进程 与 GPU进程
合成线程 将图层分为图块
图块在 栅格化线程池中 被栅格化 为位图
合成
合成线程 在所有图块被光栅化后, 生成 绘制图块命令
DrawQuad
,提交 浏览器线程浏览器线程, viz组件 接收
DrawQuad
命令, 将页面内容绘制在 内存 中,最后将 内存 显示在屏幕上
总结
- 渲染进程 将HTML转换为 DOM树
- 渲染引擎 将CSS转换为 styleSheets,计算出 DOM节点 的 样式
- 布局树 被创建,并 计算布局信息
- 图层树 被创建,由 布局树 分层而来
- 绘制列表 被根据每个图层生成, 并提交给 合成线程
- 合成线程 将图层 分为 图块,并在 光栅化线程池 中将图块转换为 位图
- 合成线程 发送 绘制图块命令DrawQuad 给 浏览器进程
- 浏览器进程 根据 DrawQuad 生成页面,并 显示 在显示器上
重排 重绘 合成
CSS文件的下载阻塞DOM树的合成
浏览器接收到HTML页面第一批数据的时候,DOM解析器开始工作
JS脚本会阻塞DOM渲染
JS外部脚本也会阻塞DOM渲染
JS脚本访问了元素样式,则会等待样式文件下载,从而阻塞DOM渲染
如果,解析过程遇到内部JS脚本非文件,会暂停解析,执行JS脚本,再继续解析;
如果,解析过程遇到外部JS脚本文件,会暂停解析,下载并执行JS脚本,再继续解析;
如果,解析过程遇到JS脚本,会暂停解析,执行JS脚本,
如果,此JS脚本访问了某元素样式,会暂停JS执行,等待样式下载,才继续执行JS.