每次你打开一个网站,你已经对上面的出现的内容习以为常,然而,在某一瞬间,你又突然对它感到好奇。
它上面的内容是如何显示出来的?
从你在地址栏输入一个 URL,到屏幕上呈现出完整的网页,这一过程看似瞬间完成,然而,背后却隐藏着浏览器与服务器之间精密协作的复杂机制。
先说结论,从url输入到页面渲染过程分为以下步骤:
- DNS 解析 :将域名(如
juejin.com)转换为对应的 IP 地址。 - 建立 TCP 连接 :通过 三次握手 ,确保浏览器与服务器之间的通信可靠性。
- 发送 HTTP 请求 :浏览器通过 TCP 连接,向服务器请求资源(如 HTML、CSS、JS)的过程。
- 服务器处理并返回响应 :服务器处理请求,返回包含资源内容的 HTTP 响应。
- 浏览器解析与渲染页面 :浏览器解析 HTML和 CSS,生成渲染树,并通过一系列操作将代码转化为网页。
- 断开连接 :TCP通过 四次挥手 终止 TCP 连接。
一、DNS 解析
当用户在地址栏输入 URL(如 https://juejin.cn/)后,浏览器会通过 DNS 解析 将域名转换为对应的 IP 地址。
名词解释
URL: 一个用于标识互联网上资源位置的地址。
IP地址 :用于标识网络中每个设备的唯一数字标签,它能够使设备相互定位和通信。
流程分析
-
浏览器先检查本地 DNS 缓存(操作系统或浏览器缓存)。
-
若无缓存,向递归 DNS 服务器发起查询,最终通过权威 DNS 服务器获取 IP 地址。
就像是你去朋友家玩,但不知道他家的地址,你先翻看自己的通讯录(本地缓存)看看是否有记录, 如果没有,就打电话问朋友(递归 DNS 服务器),朋友再查他的家庭地址(权威 DNS 服务器)告诉你。
二、建立 TCP 连接
通过 IP 地址,浏览器与服务器建立 TCP 连接,通过 三次握手 确保通信的可靠性。
名词解释
三次握手:
- 客户端向服务器发送一个
SYN(同步)消息,表示请求建立连接,并进入SYN\_SENT状态。 - 服务器接收到
SYN请求后,会回复一个SYN-ACK消息给客户端,表示同意建立连接。 - 客户端收到服务器的
SYN-ACK后,发送一个ACK(确认)消息作为回应,确认收到了服务器的SYN并完成连接的最后一步。
SYN:全称Synchronize Sequence Numbers,意味着客户端请求与服务器同步序列号,以准备建立一个连接,这是一个开始对话的信号。
SYN_SENT:表示客户端已经发出了同步请求,正在等待服务器的响应。在这个状态下,客户端期待从服务器接收到一个 SYN-ACK 作为回应。
SYN-ACK:服务器在接收到客户端的 SYN 后,会发送一个 SYN-ACK 作为响应,SYN 部分表示服务器同意同步序列号,而 ACK 部分则是对客户端 SYN 的确认。
ACK:表示客户端收到了服务器的 SYN-ACK 响应,并且双方现在都已经准备好进行数据传输。完成这一步骤后,连接建立,可正常数据通信。
举个例子:
就像是你和朋友约好见面,需要确认双方都准备好了。
你发短信:“明天下午三点在咖啡馆见,你来吗?”(SYN 请求)。
朋友回复:“我到时间一定到,你也来吧!”(SYN-ACK 响应)。
你回复:“收到,明天见!”(ACK 确认)。
三、发送 HTTP 请求
浏览器通过 TCP 连接向服务器发送 HTTP 请求报文,请求 HTML 文件及关联资源(如CSS、JS 等)。
名词解释
HTTP 请求报文:客户端(如浏览器)向服务器发送的一种数据格式,用于请求资源或执行操作,它主要由以下几个部分组成:
-
请求行 :包含请求方法(如
GET、POST)、请求的资源路径(如/index.html)、以及使用的HTTP版本(如HTTP/1.1)。 -
请求头 :提供关于请求的附加信息,如客户端类型(
User-Agent)、接受的内容类型(Accept)、主机名(Host)等。 -
请求体 :对于某些请求方法(如
POST或PUT),可能包含要发送给服务器的数据,比如表单数据或文件内容。
四、服务器处理并返回响应
服务器接收请求后,处理逻辑并返回HTTP响应报文,其中包含 HTML 内容及状态码。
名词解释
状态码:服务器通过HTTP响应报文返回给客户端的一个三位数字代码,用于表示请求的处理结果,它可以让客户端快速了解操作是否成功、需要采取什么进一步行动或是否有错误发生。
常见的状态码分类如下:
- 2xx(成功) :如
200 OK,表示请求已成功处理。 - 3xx(重定向) :如
301 Moved Permanently,表示资源已永久移动到新位置,需客户端进行额外操作以完成请求。 - 4xx(客户端错误) :如
404 Not Found,表示客户端发出的请求有误,服务器无法找到请求的资源。 - 5xx(服务器错误) :如
500 Internal Server Error,表示服务器在处理请求时发生了错误。
五、浏览器解析与页面渲染
该过程核心步骤如下图所示:
1. 解析 HTML(HTML Parser):构建 DOM 树
过程
-
字节流解析:浏览器通过网络请求获取HTML文件的字节流(如HTTP响应),根据文件的编码(如UTF-8)将其转换为字符流。
-
令牌化(Tokenization) :HTML解析器通过状态机逐字符解析字符流,识别标签名(如
<div>)、属性(如id="box")等,并生成标记(Token)。 -
DOM节点生成:每个标记会被转换为对应的DOM节点对象。
举个例子:
<div id="box"></div>
其在内存中存储格式简单描述(真实的 DOM 节点在浏览器中是一个更复杂的对象,下面只是简略版,但核心逻辑相同)为:
{
type: 'div',
attrs: {
id: 'box'
},
children: [...]
}
最终,一步步递归后,构建成一棵完整的DOM树。
关键:
- 阻塞行为:遇到
<script>标签时,解析会暂停,优先执行脚本(除非使用async或defer属性)。 - 动态更新:通过JavaScript修改DOM时,会触发DOM树的重新构建(重排)。
2. 解析 CSS(CSS Parser):构建 CSSOM 树
过程
-
样式表解析:浏览器解析
<style>标签、<link>引入的CSS文件,以及内联样式。 -
CSSOM树生成:将CSS规则转换为CSSOM树,以下列代码为例:
div#box {
color: red;
}
p {
margin: 0;
}
<div id="box">
<p></p>
其在内存中存储格式的简单描述为:
{
selectors: ["div#box", "p"],
styles: {
"div#box": {
color: "red"
},
"p": {
margin: "0"
}
}
}
关键:
- 层叠规则:通过选择器优先级(如
!important、ID选择器、类选择器)确定最终样式。 - 阻塞渲染:CSSOM的构建会阻塞渲染树的生成,直到所有样式表加载完成(除非使用
@import或异步加载)。
3. 生成渲染树(Render Tree)
过程
-
合并DOM和CSSOM:浏览器将DOM树和CSSOM树合并,生成渲染树(Render Tree)。
-
过滤不可见元素:
- 排除
display: none的元素。 - 排除不在当前视口内的元素(如懒加载图片)。
- 排除
关键:
- 渲染树的结构:仅包含可见元素及其样式信息。
- 动态更新:当DOM或CSSOM变化时,渲染树会重新生成。
4. 布局(Layout):计算几何位置
过程
-
BFC与IFC:
- BFC(块级格式化上下文) :由
overflow: hidden、float等属性触发,独立于父容器的布局。 - IFC(行内格式化上下文) :处理文本和行内元素的布局。
- BFC(块级格式化上下文) :由
-
盒子模型计算:
- 计算每个元素的
width、height、margin、padding、border等属性。 - 根据文档流(Normal Flow)确定元素的位置(如块级元素从上到下排列,行内元素从左到右排列)。
- 计算每个元素的
关键:
* **重排(Reflow)** :布局计算称为重排,是性能开销最大的阶段之一。
* **触发重排**:修改元素的几何属性(如`width`、`height`)会触发重排。
5. 分层(Layering):图层划分
过程
-
图层触发条件:
- 使用
transform、opacity、filter等属性。 - 元素设置
position: fixed或z-index。 - 视频、Canvas等特殊元素。
- 使用
-
图层管理:
- 每个图层独立绘制,修改图层内容时仅需重新绘制该图层(而非整个页面)。
- GPU加速:图层绘制由GPU处理,提升性能。
关键:
- 过度分层:过多图层会增加内存占用和合成成本,需合理使用。
6. 绘制(Paint):像素化渲染
过程
-
像素生成:
- 将图层分解为像素信息(如颜色、形状、文本),生成位图。
- 处理复杂效果(如阴影、渐变、抗锯齿)。
关键:
- 重绘(Repaint) :当元素样式变化但不影响布局时(如
color、background),触发重绘。 - 绘制开销:重绘成本较高,需避免频繁操作(如闪烁动画)。
7. 合成(Composite):最终画面输出
过程
-
图层合成:
- 浏览器将所有图层按
z-index顺序提交给GPU。 - GPU将图层合成为最终画面,并输出到屏幕。
- 浏览器将所有图层按
关键:
- 硬件加速:通过GPU合成提升性能,尤其适合动画和复杂页面。
- 优化策略:减少图层数量、避免过度合成(如不必要的透明度或阴影)。
由于篇幅太长,对于该模块内容,如果想要进行更深入的了解,欢迎阅读《# 从url输入到页面渲染(二):解析和渲染过程详解》
六、断开连接
当页面显示出内容后,TCP 通过四次挥手,终止 TCP 连接,确保双方都能安全、有序地关闭连接。
名词解释
四次挥手:
-
客户端发送
FIN:客户端(浏览器)告知服务器:“我已无数据发送,请求关闭连接。” -
服务器回应
ACK:服务器确认收到FIN,并发送ACK表示同意关闭。 -
服务器发送
FIN:服务器主动发送FIN,表示自己也无数据发送。 -
客户端回应
ACK:客户端确认收到FIN,连接彻底关闭。
FIN: TCP 协议中用于关闭连接的控制标志位(Finish),它的作用是告诉对方:“我已经完成数据发送,请求关闭连接”。
本文为作者的理解,如果内容有误,欢迎各位读者在评论区指正。
最后,都看到这了,如果觉得这篇文章对你有所帮助,不妨动动小手,点赞 + 收藏 !🌟