浏览器的解析渲染原理以及JS、CSS阻塞问题分析

输入Url地址按下回车发生了什么?

1:根据网址进行DNS解析,将相应的域名解析为IP地址
2:客户端根据IP地址去寻找对应的服务器并进行TCP三次握手,建立TCP连接
3:客户端发起HTTP请求,请求对应资源
4:服务器响应并返回相应数据(如:HTML文件)
5:浏览器将获取的HTML文档由HTML解析器解析成DOM树
6:同时由CSS解析器将CSS样式解析成CSS Rule Tree(CSS规则树)
7:将生成的DOM树和CSS规则树合并生成Rendering Tree(渲染树)
8:根据渲染树,在屏幕上对元素进行布局
9:根据渲染树,将各个元素绘制到屏幕上
10:客户端与服务器进行TCP的四次挥手

浏览器的解析渲染原理如下图过程所示:
浏览器的解析渲染原理以及JS、CSS阻塞问题分析_第1张图片

浏览器渲染网页注意事项

1:DOM的构建过程是一个深度遍历的过程,即当前节点的所有子节点都构建好以后才会去构建当前节点的下一个兄弟节点

2:渲染树和DOM不同,因为像DOM树中的display:none元素不会出现在渲染树中,但visibility: hidden会出现在渲染树中

3:DOM解析和CSS解析是同时进行,互不影响

4:渲染树的生成并不是等到DOM树和CSS规则树解析完成才开始合并,而是边解析、边合并渲染

浏览器渲染网页阻塞顺序

1:构建DOM树时,如遇到JS元素时,会阻塞DOM树和CSS规则树的构建,优先执行JS文件

2:构建DOM树时,如遇到CSS元素时,会开启异步请求线程,该线程会先下载CSS文件,再构建CSS规则树,该线程会阻塞JavaScript引擎线程,但不会阻塞DOM树的构建

3:CSS解析和JS解析互斥,也就是说JS解析时会阻塞CSS解析而CSS解析时也会阻塞JS解析

4:JS解析时,如果JS还操作了CSS,而这个CSS还没有下载或构建解析,则会延迟执行JS,直到完成CSS下载构建解析,再会继续执行JS

白话说明
浏览器在渲染网页时会开启两条线程渲染引擎线程和JS引擎线程,但这两条线程是互斥的,同时只能有一个线程在执行。也就是说在构建DOM树时,渲染引擎在执行:

当遇到JS时:渲染引擎会停止执行,控制权交给JS引擎,当执行JS代码时
如果遇到获取DOM,那么如果该DOM还没有解析,则会获取为null,如果JS代码还操作了CSS,而这个CSS如果还没有下载和构建,那么浏览器首先会阻塞JS引擎执行,然后会开启一个异步请求线程,在该线程上,去下载构建CSS规则树,CSS规则树构建完成后,再继续执行JS代码,当JS执行完以后,控制权再次交给渲染引擎去执行。

当遇到CSS元素时:也会开启异步线程,去下载构建CSS规则树,但同时也会继续构建后面的DOM树,也就是说DOM解析和CSS解析可以同时进行,但如果后面遇到JS元素,则会阻塞JS引擎线程执行,后面DOM树解析不受影响。

CSS和JS引入位置说明

1:CSS资源尽量放在head部分
2:JS资源尽量放在body结束标签之前
3:CSS资源尽量优先于JS资源引入

引入位置解释
1:因为CSS解析和DOM解析可以同时进行,所以CSS资源放在头部不会影响DOM解析,而且放在头部也会优先开始加载CSS样式,在渲染DOM的时候也已经知道了自己的样式,所以一次就可渲染成功,如果将CSS放在底部,那么会优先渲染DOM,而浏览器为了更好的用户体验,渲染引擎会尝试尽快在屏幕上显示内容,也就是说渲染引擎会边解析、边渲染、边布局显示,已尽快减少白屏时间,所以随着CSS规则树的构建,还需要对之前渲染树重新渲染,可能会导致回流和页面跳动。

2:JS放在body标签结束之前,首先可以确保能取到需要操作的DOM对象,也可缩短因JS阻塞。而造成的白屏时间,提升用户体验。因为如果把JS放在head部分,JS运行会阻塞DOM树和CSS树构建,导致白屏时间延长,影响用户体验。

3:因为JS在运行时,如果需要操作CSS,但该CSS还没有下载和构建,则首先会阻塞JS线程,然后开启新线程去下载解析构建CSS规则树,再执行JS代码

浏览器引擎说明

之前浏览器内核分两个部分:渲染引擎和JS引擎,但由于JS引擎越来越独立,所以现在通常所谓的浏览器内核也就单指浏览器所采用的渲染引擎了

渲染引擎:负责对网页语法的解释(如标准通用标记语言下的一个应用HTML、JavaScript)并渲染(显示)网页
常见渲染引擎有Chrome、Safar采用Webkit,Firefox火狐采用Gecko,IE采用Trident。(目前Chrome开始采用Blink,IE采用Edge)

JS引擎:单线程引擎,负责执行JS代码
常见JS引擎有Chrome采用V8引擎,Safari采用Nitro,Firefox采用SpiderMonkey,微软采用JScript引擎

回流(reflow 重排)与重绘(repaint)

回流:又称重排,当渲染树的一部分或全部元素结构发生改变(增加、删除、位置改变,显示或隐藏),浏览器都需要重新计算一遍DOM结构,重新对当前的页面进行渲染,这就是回流。每个页面至少需要一次回流,就是在页面第一次加载的时候

重绘:当渲染树中的元素只是外观风格(背景色,字体颜色,边框颜色)改变,而不影响周围和内部布局时,这时浏览器只会重画某一部分,这就是重绘

注意
1:回流必定触发重绘,而重绘不一定触发回流
2:回流要比重绘更花费时间,也就更影响性能。所以在写代码时,要尽量避免过多的回流
3:display:none会触发回流,因为元素隐藏,布局发生了改变,而visibility:hidden只是隐藏元素,但还占着布局控件,所以只会发生重绘

如何减少回流和重绘

1:为需要多次回流的元素设置绝对定位或固定定位来脱离文档流,形成新的图层来限制回流和重绘的范围(如轮播图)

2:避免一条一条的修改样式,最好将样式定义为class并一次性更改

3:避免循环操作DOM。创建一个documentFragment或div,在它上面应用所有DOM操作,最后再把它添加到window.document

4:对一个元素进行复杂操作时,可以先隐藏,处理完成后再显示,这里所谓的隐藏就是让元素不存在于render tree中(先display:none 隐藏元素,然后对该元素进行所有的操作,最后再显示该元素。因对display:none的元素进行操作不会引起回流、重绘。所以只要操作只会有2次回流)

5:用transform做形变和位移

6:不要使用table布局,因为table的每一个小改动都会导致整个table重新布局

性能优化建议

1:减少HTTP请求数(如CSS精灵)

2:样式文件放在head中,脚本文件放在body标签结束前,这样可减少白屏时间,提升用户体验

3:避免一条一条的修改样式,最好将样式定义为class并一次性更改

4:资源合并与压缩(尽可能合并外部脚本,图片压缩)

5:为需要多次回流的元素设置绝对定位或固定定位来脱离文档流,形成新的图层来限制回流和重绘的范围(如轮播图)

6:对一个元素进行复杂操作时,可以先隐藏,处理完成后再显示,这里所谓的隐藏就是让元素不存在于render tree中

7:避免循环操作DOM。创建一个documentFragment或div,在它上面应用所有DOM操作,最后再把它添加到window.document

8:为图片指定大小,减少回流

9:少用全局变量,尽量使用局部变量

10:尽量用transform来做形变和位移,以减少回流

11:图片懒加载

12:对页面做节流和防抖

13:尽量减少在JS中进行DOM操作

14:简化并优化CSS选择器,尽量将嵌套层减少到最小

15:类型转换:把数字转换成字符串使用number + “” 效率最高

参考文章
https://blog.csdn.net/lxsjh/article/details/79158820
https://www.jianshu.com/p/b6b42fd3f80e

你可能感兴趣的:(前端)