浏览器渲染过程
浏览器采用流式布局模型(Flow Based Layout)
1. DOM 树:解析 HTML 构建DOM 树
当浏览器从服务器接收到HTML文档后,会开始从上到下解析HTML文档。在这个过程中,浏览器会将HTML标签转换为DOM(文档对象模型)节点,并构建出一个DOM树。这个DOM树是浏览器内部表示页面结构的一种方式,它包含了页面中的所有元素以及它们的属性和关系。
2. CSS 树:解析 CSS 构建 CSSOM树
同时,浏览器也会解析HTML中引用的CSS样式表。CSS样式表定义了页面中元素的样式和布局。浏览器会将这些样式信息解析为CSSOM(CSS对象模型)树。CSSOM树和DOM树是并行构建的,但它们的构建过程相互独立。
3. 渲染树:CSSOM 和 DOM 一起生成 Render Tree(渲染树)
一旦DOM树和CSSOM树都构建完成,浏览器会开始合并这两棵树,形成一个渲染树。渲染树只包含需要显示在屏幕上的节点和它们的样式信息。这个过程会排除掉那些对最终渲染结果没有影响的节点,比如display属性为none的元素。
4. 布局(layout):重排/回流
根据Render Tree浏览器就知道网页中有哪些节点,以及各个节点与 CSS 的关系,从而知道每个节点的位置和几何属性(重排)
,完成布局计算。
浏览器会采用流式处理的方法,只需要一次pass绘制操作就可以布局所有的元素。
5. 绘制(Paint):重绘
浏览器会根据渲染树和布局计算的结果,将每个节点绘制到屏幕上。这个过程称为绘制或渲染。(重绘)
绘制过程中,浏览器会考虑各种视觉效果,比如阴影、渐变等,以呈现出最终的页面效果。
过程如下图:
过程1、2、3非常快,但是4和5比较耗时
“重排” 和 “回流”是一个意思,指的是重新执行步骤4
“重绘” 指重新执行步骤5
.
DOM 树 和 渲染树 的区别:
DOM 树与 HTML 标签一一对应,包括 head 和隐藏元素(display:none
)
渲染树不包括 head 和隐藏元素(display:none
),大段文本的每一个行都是独立节点,每一个节点都有对应的 css 属性
浏览器阻塞
自上而下解析HTML,逐渐构建起DOM tree,遇到style、link标签,会下载解析样式表,同时构建CSSOM tree,不会阻塞html的解析。但是遇到script标签,它会立即下载并执行得到的脚本,会阻塞HTML的解析。直到脚本里的同步代码部分(settimeout等异步操作之外的代码)执行完之后,再接着解析接下来的HTML。
直到将整个HTML文档的最后一个标签解析完毕,DOM tree生成完毕。然后CSSOM tree 、render tree生成,开始渲染。
1. js加载会阻塞DOM树的解析和渲染
如果把js放在页面顶部,下载和解析js的时间里面,dom迟迟得不到解析和渲染,浏览器一直处于白屏,所以把JavaScript文件放在页面底部更有利于页面快速呈现。
2. css加载不会阻塞DOM树的解析但会阻塞DOM树的渲染
如果把css文件引用放在HTML文档的底部,浏览器为了防止无样式内容闪烁,会在css文件下载并解析完毕之前什么都不显示,这也就会造成白屏现象。(但是在firefox浏览器中测试,会出现样式闪烁,这也算是不同浏览器的权衡吧,要么等css全解析完一起显示,要么先显示然后css解析完再重新画上新样式)
当css文件放在<head>
中时,虽然css解析也会阻塞后续dom的渲染,但是在解析css的同时也在解析dom,所以等到css解析完毕就会逐步的渲染页面了。
3. css加载会阻塞后面js语句的执行
因此,为了避免让用户看到长时间的白屏时间,我们应该尽可能的提高css加载速度,比如可以使用以下几种方法:
- 使用CDN(因为CDN会根据你的网络状况,替你挑选最近的一个具有缓存内容的节点为你提供资源,因此可以减少加载时间)
- 对css进行压缩(可以用很多打包工具,比如webpack,gulp等,也可以通过开启gzip压缩)
- 合理的使用缓存(设置cache-control,expires,以及E-tag都是不错的,不过要注意一个问题,就是文件更新后,你要避免缓存而带来的影响。其中一个解决防范是在文件名字后面加一个版本号)
- 减少http请求数,将多个css文件合并,或者是干脆直接写成内联样式(内联样式的一个缺点就是不能缓存)
defer和async
js加载会阻塞DOM树的解析和渲染,但<script>
标签的async和defer属性可以改变阻塞HTML解析的情况(但是较低版浏览器不支持,所以最佳的实践是,将<script>
放在</body>
前)。
async和defer
对于内联JavaScript是无效的
defer
设置了defer的script外链文件,在下载js文件期间不会阻塞HTML的解析,而且等js下载完毕时若HTML还没解析完毕,js会等到HTML文档解析完毕后再执行。如果有多个js下载文件,那么执行时也是按照顺序执行。
async
设置了async的script外链文件,在下载js文件期间不会阻塞HTML的解析,但是js下载完毕之后就会立即执行,无论现在HTML是否正在解析。
x