浏览器渲染机制

# 常见的浏览器渲染引擎

# 渲染引擎

能加载HTML/css/javascript文本和对应资源文件转换成图像结果

# 渲染器种类

渲染引擎 浏览器
Trident IE、Edge(旧)
Geoko Firefox
Webkit Safari
Blink(Webkit form) Chrome, Opera,Edge(新)

# 浏览器的工作流程

image.png

webkit的主要流程

image.png

我们围绕这张图,看下浏览器是如何渲染页面的技术细节

  • 解析dom,生成dom tree(并行)
  • 解析css,生成cssom tree(并行)
  • 将dom树和cssom规则合并在一起生成渲染树
  • 遍历开始布局,计算节点位置大小,生成布局树
  • GPU工作,按照布局树规则在屏幕上绘制页面

# 构建dom树

浏览器接收到html文档之后,遍历文档所有节点,根据深度优先遍历的算法,HTML解析器将HTML标记解析成DOM Tree(就是我们审查元素时的层级结构)。

# 构建csscom树

css Parse 将每一css 文件都解析成一个styleSheet对象,每个对象包含style Rules,这个也就是所谓的cssom。

不知道大家在这里会不会有和我一样的疑问,既然cssom是为了dom而存在的,为什么不在dom解析的时候,就将对应的样式添加到dom上呢?而且css具有很高的优先级,css会阻塞任何的渲染,在css解析前,页面上不会有任何反应。我想到的解释是,如果css解析之前就渲染了页面,那么每个页面都是无样式的,过一会却突然有了样式,整个页面的渲染就会很糟糕。

# 生成Render Tree

这个时候,浏览器会将DOM和CSSDOM结合起来生成Render Tree(渲染树)

# 生成布局树 Layout

创建渲染树之后,构建布局树,分两个部分:

# 回流(reflow)

浏览器布局发生改变,需要倒回去重新渲染,这个过程叫做回流(reflow),从root往下递归计算,来确认是渲染树的整体还是一部分发生改变。

引起回流的一些操作

  • 页面第一次渲染(初始化)
  • DOM树变化(如:增删节点)
  • Render树变化(如:padding改变)
  • 浏览器窗口resize
  • 获取元素的某些属性:offsetLeftoffsetTopoffsetWidthoffsetHeightscrollTop/Left/Width/HeightclientTop/Left/Width/Height、调用了getComputedStyle()

image.png

# 重绘(repaint)

改变某个元素的背景色、文字颜色、边框颜色等等不影响它周围或内部布局的属性时,屏幕的一部分要重画,但是元素的几何尺寸和位置没有发生改变,这个过程叫做重绘(repaint)

回流必定引起repaint重绘,重绘可以单独触发

  • 背景色、颜色、字体改变(注意:字体大小发生变化时,会触发回流)

image.png

# 优化

# 减少reflow、repaint触发优化

  • 用transform做形变和位移可以减少reflow
  • 避免逐个修改节点样式,尽量一次性修改
  • 使用DocumentFragment将需要多次修改的DOM元素缓存,最后一次性append到真实DOM中渲染
  • 可以将需要多次修改的DOM元素设置display:none,操作完再显示。(因为隐藏- - 元素不在render树内,因此修改隐藏元素不会触发回流重绘)
  • 避免多次读取某些属性
  • 通过绝对位移将复杂的节点元素脱离文档流,形成新的Render Layer,降低回流成本

# 浏览器内核(渲染进程)中线程之间的关系

image.png

为了防止渲染出现不可预期的结果,GUI线程和JS引擎线程互斥

js是可以操作dom的,如果修改时,在GUI正在渲染,这个时候GUI线程会被挂起,保存在一个队列中,等待js引擎空闲时立即被执行

问:CSS加载会阻塞DOM树的解析,渲染吗? 这里说的是头部引入css的情况

答:根据上面的流程图可以看到,dom树和cssom是互相解析的,但是在生成render树的时候,需要等待css解析完,所以CSS加载不会阻塞DOM树的解析,但是会阻塞DOM树的渲染

问:CSS和JS会互相阻塞吗?

答:因为GUI线程和JS引擎线程互斥,我们可以分别尝试分别把js和css放在上面

  1. script标签在style上面使用alert语句,页面不加载,阻塞了css解析
  2. style在面,使用慢网速加载cdn的css样式,样式展示前,js不执行,阻塞了js的执行

结论,CSS加载会阻塞后面JS语句的执行,所以在开始学习前端时,会建议大家将script标签放在body之后,防止影响页面渲染。

# 相关链接

https://juejin.cn/post/6940210613662531592

上次更新: 2022/04/15, 05:41:26
×