前言
从大的方向来说,总共分为 4 个步骤,其中大步骤又包含了一些小步骤。本文会简要介绍各个步骤,但不会对其进行深入探究。
一、URL解析
这一步比较容易理解,在浏览器地址栏输入url
后,浏览器会判断这个url的合法性
,以及是否有可用缓存
,如果判断是 url
则进行域名解析,如果不是 url
,则直接使用搜索引擎搜索。
二、域名解析
输入 url
并点击确定访问后,第二步是进行DNS域名解析
,如果输入的是 ip 地址
,则可以省略这一步
,因为DNS域名解析,就是把域名解析成ip地址。
域名系统(DNS): 域名系统是互联网的一项服务,是一个将域名和ip地址相互映射的分布式数据库。
机器只能识别ip地址
,但是对于使用者来说,ip地址
是不容易被记忆的,为了能够让人们更轻松的记住网站地址
,于是就有了域名系统
,每一个域名都有一个对应的ip地址
。
三、建立TCP连接
这一步就是常说的三次握手
与四次挥手
,在说之前,需要先了解什么是TCP
,以及客户端和服务端的几种状态。
TCP: 传输控制协议(Transmission Control Protocol),是一种面向连接的、可靠的、基于字节流的传输层通信协议。
SYN: 同步序列编号(Synchronize Sequence Numbers),是TCP/IP建立连接时使用的握手信号。1表示建立连接。
FIN: TCP报头的码位字段(Function Item Number),值为1时表明发送方字节流结束,用于关闭连接。
ACK: 确认字符 (Acknowledge character),在数据通信中,接收站发给发送站的一种传输类控制字符,表示发来的数据已确认接收无误。
ISN/seq: 初始化序列号(Initial Sequence Number),由客户端或者服务器端创建的随机序列号。ISN不能设置为固定值,否则容易被攻击者猜到后续的确认号。
客户端的三种状态: CLOSED
(关闭-默认状态)、SYN_SENT
(请求连接)、ESTABLISHED
(连接成功)
服务端的三种状态: LISTENING
(监听-默认状态)、SYN_RCVD
(SYN_Received 等待请求确认)、ESTABLISHED
(连接成功)
三次握手
- 客户端向服务器端发送一段带有
SYN
标志的数据包,请求建立连接,并将自身状态改为SYN_SENT(请求连接)
状态;
报文内容: SYN=1,seq=x(此处seq为
客户端
随机生成的序列号,为了方便理解,我们假设为x)
- 服务器端收到来自客户端的TCP报文后,结束
LISTENING(监听)
状态,并返回一段带有SYN + ACK
标志的数据包,表明已收到来自客户端的数据,同时将自身状态改为SYN_RCVD(等待请求确认)
状态;
报文内容: SYN=1, ACK=1, seq=y, ack=x+1(确认字符为1,序列号为x+1,此处seq为
服务器端
随机生成的数值,为了方便理解,我们假设为y)
- 客户端收到来自服务器端的确认收到数据的报文后,再次发送一段报文,表明客户端已收到服务器端的确认信息,同时将自身状态改为
ESTABLISHED(连接成功)
状态,服务器端收到报文后,也将自身状态改为ESTABLISHED(连接成功)
状态。
报文内容: SYN=1, seq=x+1, ack=y+1
注意:确认字符 +1
是为了方便接收方确认,大写表示状态,小写表示值。
四次挥手
- 客户端向服务器端发送一段带有
FIN
标志的数据包,请求断开连接,并停止继续发送数据,主动断开TCP
连接,同时将自身状态改为FIN_WAIT1
,等待服务器端确认;
报文内容: FIN=1, seq=x
- 服务器端收到
FIN
数据包后,返回一段带有ACk
标志的数据包,表明可以断开连接,同时将服务器状态改为CLOSE_WAIT
,客户端收到此报文后,状态改为FIN_WAIT2
;
报文内容: ACK=1, seq=y, ack=x+1
- 如果服务器端也准备断开连接,则会向客户端发送一段带有
FIN
标志的数据包,此时服务器状态为LAST_ACK
,等服务器发送完所有数据后,再次向客户端发送FIN + ACK
报文,确认断开连接;
报文内容: FIN=1, ACK=1, seq=z, ack=x+1
- 客户端收到
FIN + ACk
报文后,再次向服务器端发送ACK
报文回应,等待一段时间后,如果没有收到来自服务器端的回应则直接进入CLOSE
状态,服务器端在收到ACK
报文后,直接进入CLOSE
状态,不做回应。
报文内容: ACK=1, seq=x+1, ack=z+1
四、页面渲染
最后一步就是页面渲染了,这是一个很复杂的过程。
1. 解析HTML,并搭建DOM树
浏览器接收到 html 文件
后将其解析成 DOM 树
,这个解析从接收到 html 文件
的时候就已经开始了,并不是等到接收完成后才开始,解析的过程是自上而下,先解析当前节点的所有子节点,再解析兄弟节点及其子节点。
2. 解析CSS,并搭建样式树
浏览器将所有的 css
包括其自身的样式全部解析成样式树,解析的过程中会自动去掉浏览器不能识别的样式。
3. 将HTML和CSS结合,搭建Render树(渲染树)
将每个 HTML
节点与其对应的 CSS
样式结合,搭建 Render 树
。
4. 根据渲染树计算布局
根据已经生成好的 Render 树
,计算每个节点的颜色、尺寸及位置等信息。
5. 将元素绘制到页面上
将计算好的节点绘制到页面上,这个过程可能会产生 重绘
和 重排(回流)
,要尽量避免回流。
重绘: 因为元素的颜色,字体等不改变尺寸及位置的样式改变而重新绘制,性能消耗较小
重排(回流): 因为元素的尺寸或位置改变而导致的重新绘制,这种可能会导致多处元素重新绘制,性能消耗较大
注意:
CSS
不会阻塞DOM 树
的搭建,但是会阻塞页面的渲染,这是因为页面渲染需要先计算好节点的样式。HTML
文件中的外部资源会提前加载,不会等到渲染完成后再加载。JS
会阻塞HTML
的解析,因为浏览器不知道JS 脚本
的内容,但JS 脚本
有可能会操作DOM
,为了避免重复渲染,浏览器会先加载JS 脚本
。CSS
会阻塞JS
的执行,因此需要将<script>
标签放在<link>
标签之前。
END