浏览器渲染逻辑和重绘、回流解析

浏览器从输入url 到 渲染出界面 中间经历的过程

1 DNS 查询

2 TCP 连接

3 HTTP 请求即响应

4 服务器响应

5 客户端渲染

浏览器是如何渲染UI的?(客户端的渲染)

1 浏览器接收到 html 和 css 文件 ,并对html进行解析,生成 DOM 树 (遇到link,script 会造成阻塞)

2 同时对css进行解析,生成 CSSOM 树

3 将DOM树 和 CSSOM树 合成 Render 树(渲染树)

4 根据渲染树来布局,以计算每个节点的几何信息。(定位坐标和大小,是否换行,各种position, overflow, z-index属性)

5 调用GPU进行绘图,遍历render tree的每个节点,将元素显示到屏幕上

css的加载和解析不会阻塞html文档的解析
css的解析会阻塞js的执行,必须等到CSSOM生成后才能执行js
js的执行会阻塞html文档的解析
html一边解析一边显示
css必须完全解析完毕才能进入生成渲染树环节

重绘

Repaint——屏幕的一部分要重画,比如某个CSS的背景色变了。但是元素的几何尺寸没有变。

回流、重排

Reflow——意味着元件的几何尺寸变了,我们需要重新验证并计算Render Tree。是Render Tree的一部分或全部发生了变化。这就是Reflow,或是Layout。(HTML使用的是flow based layout,也就是流式布局,所以,如果某元件的几何尺寸发生了变化,需要重新布局,也就叫reflow)reflow 会从这个root frame开始递归往下,依次计算所有的结点几何尺寸和位置,在reflow过程中,可能会增加一些frame,比如一个文本字符串必需被包装起来。

回流的原因:
1 Initial。网页初始化的时候。

2 Incremental。一些Javascript在操作DOM Tree时。

3 Resize。其些元件的尺寸变了。

4 StyleChange。如果CSS的属性发生变化了。

5 Dirty。几个Incremental的reflow发生在同一个frame的子树上。

注: 一般来说,浏览器会把这样的操作积攒一批,然后做一次reflow,这又叫异步reflow或增量异步reflow。但是有些情况浏览器是不会这么做的,比如:resize窗口,改变了页面默认的字体,等。对于这些操作,浏览器会马上进行reflow。

link 标签会阻塞html的解析
script 标签会阻塞html的解析
由于 DOM树和CSSOM才能生出渲染树,所以 css越早提供越好,一般推荐link标签写到head中,script 标签写到文档底部
script标签异步加载 defer 、 async属性,不会影响DOM树的构建

阻塞问题
script标签会阻塞DOM树的构建
CSSOM 的构建会阻塞 script标签中js的执行 (假如浏览器发现js中)

defer
<script src="app1.js" defer></script>
<script src="app2.js" defer></script>
<script src="app3.js" defer></script>

defer 属性表示延迟执行引入的 JavaScript,即这段 JavaScript 加载时 HTML 并未停止解析,这两个过程是并行的。整个 document 解析完毕且 defer-script 也加载完成之后(这两件事情的顺序无关),会执行所有由 defer-script 加载的 JavaScript 代码,然后触发 DOMContentLoaded 事件。

defer 不会改变 script 中代码的执行顺序,示例代码会按照 1、2、3 的顺序执行。所以,defer 与相比普通 script,有两点区别:载入 JavaScript 文件时不阻塞 HTML 的解析,执行阶段被放到 HTML 标签解析完成之后。

async
<script src="app.js" async></script>
<script src="ad.js" async></script>
<script src="statistics.js" async></script>

async 属性表示异步执行引入的 JavaScript,与 defer 的区别在于,如果已经加载好,就会开始执行——无论此刻是 HTML 解析阶段还是 DOMContentLoaded 触发之后。需要注意的是,这种方式加载的 JavaScript 依然会阻塞 load 事件。换句话说,async-script 可能在 DOMContentLoaded 触发之前或之后执行,但一定在 load 触发之前执行。

从上一段也能推出,多个 async-script 的执行顺序是不确定的。值得注意的是,向 document 动态添加 script 标签时,async 属性默认是 true

原文地址:https://www.cnblogs.com/honkerzh/p/13814839.html