一、网页的解析过程
参考网址: https://blog.csdn.net/u012804784/article/details/125818520
1.1 DNS解析
- 查本地hos是否有对应ip
- host没有,则查本地DNS解析器缓存
- 本地DNS解析器缓存没有,则查找本地DNS服务器
- 本地DNS服务器没有,则请求根域名服务器
- 根据根服务器,连接到相应的主机域名服务器
1.2 根据IP建立TCP连接
-
三次握手
-
发送HTTP请求
-
若是HTTPS,则需要进行TSL协商,且会检查HTTP的请求头
-
关闭连接(四次挥手)
-
根据接收到的数据包解析HTML文档 5.1. HTML解析器,根据深度遍历原则,将HTML解析成DOM树
- CSS解析器,CSS解析成CSS Rule Tree(CSS规则树)
- JS代码解析,将JS代码进行解析并应用到布局中,呈现出响应式的结果
- 根据DOM树与CSSOM树构建出响应的render Tree
- 重排与重绘(看文章第三点)
- 绘制。遍历render Tree,并调用硬件图形API来绘制每个节点到页面上
-
显示页面
二、浏览器内核
- Trident:IE、360浏览器、搜狗高速浏览器、百度浏览器、UC浏览器
- Gecko:Mozilla Firefox
- Webkit:Safari、360极速浏览器、搜狗高速浏览器、移动端浏览器(Android、IOS)
- Webkit->Blink:Google Chrome、Edge
浏览器内核通常指的是浏览器的排版引擎,包括:
- 浏览器引擎
- 页面渲染引擎
- 样板引擎
三、浏览器渲染流程
3.1 图示
参考网址: https://web.dev/howbrowserswork/
3.2 解析过程
-
解析HTML文件
-
- 生成DOM
-
遇到css文件
-
- 会开一个线程(不阻塞HTML解析过程)
- 下载css文件
- 解析css文件
- 生成对应的CSSOM(CSS规则树)
-
将DOM树与CSS规则树合成,生成Render Tree(渲染树)
-
渲染树开始进行布局
-
将每个节点绘制到屏幕上
四、回流和重绘解析
4.1 回流/重排
第一次确定节点的大小和位置,称之为布局。之后对节点的大小、位置修改重新计算的行为,就称之为回流/重排。
可能引起回流的情况
-
DOM结构发生变化(新增、删除节点)
-
改变了布局,css属性如下
-
- width
- height
- padding
- font-size
- ......
-
改变了窗口的尺寸
4.2 重绘
第一次渲染内容称之为绘制。之后重新渲染称之为重绘。
可能引起重绘的情况
- 修改颜色、样式(直线、点线切换)等
4.3 总结
-
要尽量避免减少回流
-
- 尽量一次性修改样式、通过class修改
- 避免频繁操作DOM
- 避免通过getComputedStyle获取尺寸、位置等信息
- 对某些元素使用position的absolute或者fixed
-
-
- 这样开销会相对较小,不会对其他元素造成影响
-
五、合成和性能优化
-
绘制的过程,可以将布局后的元素,绘制到多个图层中(浏览器的优化手段)
-
默认情况下,标准流的内容是被绘制在同一个图层中的
-
一些特殊属性会创建新的图层,且新的图层可以利用GPU加速绘制
-
- 这是因为每个合成层都是单独渲染的
-
生成新的图层的常见属性
-
- 3D/执行动画的情况下使用transform
- video、canvas、iframe
- opacity 动画转换
- position:fixed
- animation、transition下设置opacity、transform
-
注意:生成新图层能提高性能,但是是以内存为代价,要适当使用
Script元素与页面解析之间的关系
-
首先,若解析HTML过程中遇到了Script元素,是不会继续构建DOM树
-
- 会停止继续构建,先下载JS代码,执行JS脚本
- JS结束后,再继续解析HTML
-
原因
-
- JS有操作DOM的功能,若不先执完JS,则可能频繁操作DOM导致回流和重绘,导致性能降低
六、defer和async属性
6.1 defer
使用了defer属性,浏览器不需要等待脚本下载,而会去继续解析HTML,构建DOM树
- 若脚本提前下载好,则等待DOM Tree构建完成,在DOMContentLoaded事件之前先执行defer中的代码
注意事项:
- 多个defer的script文件,是会按照顺序来执行的
- 推荐把有defer的script文件放在head当中
6.2 async
-
作用:让脚本完全独立
-
- HTML解析不因async脚本而阻塞
- 但多个async脚本不能保证顺序,不会等待其他脚本
- 不能保证在DOMContentLoaded事件之前或之后执行