【浏览器】关于地址栏输入URL到页面展现经历了哪些过程?
前言
关于 《地址栏输入URL 到页面展现经历了哪些过程》 这个问题是一个老生常谈了,无论是在面试中,还是说工作处理问题,都会用的上,最近在研究相关的内容,所以就我的知识进行了一个梳理,后面理解深入还会补充,或者也可以在评论区留言,我会看到的哦!
简单概括性的回答:
主要是两大部分工作,一部分是网络部分,一部分是浏览器渲染部分
一、网络部分
总结概括如下:
1. 解析url并且判断其合法性
2. DNS解析url到指定的ip
3. 建立TCP连接(3次握手)
4. 发送HTTP请求(请求行/头/体)(查询http缓存阶段见下图)
5. 服务器处理收到的请求,将数据返回浏览器
6. 浏览器收到HTTP响应
7. 浏览器解析并渲染页面
8. 关闭TCP连接
关于请求的步骤如下图:

下面就上述步骤中的一些需要重点理解的点,来展开讲讲。
1. 解析url并且判断其合法性
浏览器会先进行
url解析,会判断输入的是一个合法的url还是一个待搜索的关键词
不合法:如果输入的 URL 中的协议或者主机名不合法,将会把地址栏中输入的内容传递给搜索引擎。
合法:检验地址合法后,浏览器会检查URL中是否出现了非法字符,如果存在非法字符,则对非法字符进行转义后再进行下一过程。
2. DNS解析url的过程
查找过程如下:
-
本地电脑检查浏览器缓存中有没有这个域名对应的解析过的
ip地址,如果缓存有,解析结束 -
缓存中没有数据,查找操作系统缓存中是否有这个域名对应的解析结果
-
前两个都没有,操作系统会把这个域名发送给这个本地DNS服务器
-
本地没有,去根DNS服务器请求解析
-
根服务器返回给本地一个顶级DNS服务器地址,拿到后向顶级DNS服务器发送解析请求
-
接受请求查询并返回此域名对应的
Name Server域名服务器的地址 -
Name Server根据映射关系表找到目标ip,返回该域名对应的
IP和TTL值,本地DNS服务器会缓存一份这个域名和IP的对应关系,缓存时间由TTL值控制。 -
把解析的结果返回给本地电脑,本地电脑根据TTL值缓存在本地系统缓存中
迭代查询和递归查询的区别:

3. 关于TCP连接的三次握手和四次挥手
-
从最开始双方都处于
CLOSED关闭状态。 -
客户端主动请求建立连接,发送
SYN到服务端 , 自己变成了SYN-SENT状态。 -
服务端接收到请求,针对客户端的
SYN的确认应答,返回SYN和ACK(对应客户端发来的SYN),并请求建立连接,自己变成了SYN-REVD。 -
客户端收到服务端的请求,对服务端
SYN的确认应答,并发送ACK给服务端,自己变成了ESTABLISHED状态; -
服务端收到
ACK之后,也变成了ESTABLISHED状态。
另外需要提醒你注意的是,SYN 是需要消耗一个序列号的,下次发送对应的 ACK 序列号要加1,因为
凡是需要对端确认的,一定消耗TCP报文的序列号。


4. 握手为什么是三次握手不是四次?
三次握手的目的是确认双方发送和接收的能力,那四次握手可以嘛?
当然可以,100 次都可以。但为了解决问题,三次就足够了,再多用处就不大了。
5. 三次握手过程中可以携带数据么?
首先说答案:第三次握手的时候,可以携带。前两次握手不能携带数据。
如果前两次握手能够携带数据,那么一旦有人想攻击服务器,那么他只需要在第一次握手中的 SYN 报文中放大量数据,那么服务器势必会消耗更多的时间和内存空间去处理这些数据,增大了服务器被攻击的风险。第三次握手的时候,客户端已经处于ESTABLISHED状态,并且已经能够确认服务器的接收、发送能力正常,这个时候相对安全了,可以携带数据。
6. 挥手为什么是四次,三次不行吗?
答案:不可以
是因为挥手要保证双方都确认断开。所以每一步的反馈就必须干净利落,而不能像握手一样耦合在一起,例如:客户端申请断开连接后,服务端返回确认,此时只能代表客户端不会再向服务器发送信息,但不代表它不可以接收信息。所以如果双方都要断开,就要对每一步的请求进行确认,而不能耦合在一起,所以三次不可以。
7. 在发送http请求时会先进行缓存查询,那么什么是http缓存?
http缓存指的是: 当客户端向服务器请求资源时,会先抵达浏览器缓存,如果浏览器有要请求资源的副本,就可以直接从浏览器缓存中提取而不是从原始服务器中提取这个资源。
常见的http缓存只能缓存get请求响应的资源,对于其他类型的响应则无能为力,所以后续说的请求缓存都是指get请求
分类:
- 根据是否需要再请求:可分为强制缓存和协商缓存,强制缓存如果生效,不需要再和服务器发生交互,而协商缓存不管是否生效,都需要与服务端发生交互;
- 根据是否可以被单个或者多个用户使用来分类,可分为私有缓存和共享缓存
在强制缓存时:cache-control的优先级要高于expirse,原因如下:
expirse是相对于服务器时间的,cache-control和max-age是相对于上次返回请求结果的时间
在协商缓存时,ETag的优先级是高于Last-Modifined,原因如下:
-
某些服务器不能精确得到文件的最后修改时间, 这样就无法通过最后修改时间来判断文件是否更新了。
-
某些文件的修改非常频繁,在秒以下的时间内进行修改
Last-Modified只能精确到秒。 -
一些文件的最后修改时间改变了,但是内容并未改变。 我们不希望客户端认为这个文件修改了。
关于缓存的细节如下图:
二、浏览器渲染部分
渲染过程是指将我们的
htmlcssjs的代码通过复杂运算,转换成像素展示到屏幕上。

前提是先通过浏览器的网络线程去获取
HTML,当收到HTML文档后,会生成一个渲染任务,交由渲染主线程的消息队列。 然后在事件机制的作用下,渲染主线程取出消息队列中的渲染任务,开启渲染流程。
渲染流程分为多个阶段:
每个阶段性任务都会有输出,作为下一步任务的输入。
总结概括:

html解析:解析整个html内的所有内容,输出DOM和CSSOM树- 样式计算:合并
DOM和CSSOM树,计算得到初步的样式 - 布局:将
render树通过计算相对大小、位置等信息,得到layout树 - 分层:在这一步将得到最终样式的树进行分层处理,方便后面有操作或更新时的最小影响
- 绘制:将已经分层的内容生成指令集,每个指令代表本层是如何进行绘制,到此渲染主线程任务结束
- 分块:将已经分层好的内容进行颗粒度再小的分块,此时交由合成线程,合成线程会开辟多个线程同时进行
- 光栅化: 在此步骤将我们已经分块好的内容交由
GPU进行光栅化,这一步会得到一个一个的位图块儿 - 画:将我们得到的一堆位图块进行最终合并画到屏幕上
1. 解析html 和 css
先将字符串解析转换成对象结构,方便后续操作。在这一步会产生两棵树:解析
html生成dom树 ,解析CSS生成CSSOM树(包含有内部样式表、外部样式表,内联样式表,浏览器默认样式表等内容 )

什么是预解析?
浏览器在开始解析前,会启动一个预解析道线程,率先下载
HTML中的外部CSS文件和外部的JS文件。预解析线程快速浏览,找到CSS,通知网络线程去下载CSS,下载完去交给预解析线程去解析,解析完再回给渲染主线程生成CSSOM树。主要目的:提高整体解析效率。
CSS会不会阻塞html解析?
如果主线程解析到
link的位置,此时外部的CSS文件还没有下载解析好,主线程不会等待,继续解析后续的HTML,当CSS解析完成后,直接交给主线程取生成CSSOM树即可。这是因为下载和解析CSS的工作是在预解析线程中进行的。这就是CSS不会阻塞HTML解析的根本原因。

CSS会不会阻塞渲染?
因为当
css树没有构建完成,页面是不会渲染到浏览器的,需要将它尽早、尽快地下载到客户端,以便缩短首次渲染的时间,尽量减少样式嵌套,如果时间过长会导致白屏。
CSS优化方案
-
将css文件放在页面最上面
-
减少使用 * 通配符
-
尽量减少页面重排、重绘
-
尽量少的使用
@import,而是使用link,link是同步加载 -
删除冗余代码
-
如果值为
0,可以不写单位 -
减少嵌套不超过
3层,可以尽量多的使用继承
js会不会阻塞html解析?
如果主线程解析到
script位置,会停止解析html,转而等待js文件下载好,并将全局代码解析执行完成后,才能继续解析html。这是因为js代码的执行过程可能会修改当前的DOM树,所以DOM树的生成必须暂停,这就是js会阻塞html解析道根本原因。

js优化方案:
-
将
js放到页面底部,当html解析完再去解析js -
异步加载:设置
defer,当遇到defer标识会先进行下载但不执行,等html渲染完成后再执行
图片会不会阻塞渲染?
图片不会阻塞渲染,因为浏览器有一个单独的渲染进程去渲染图片,是并行的,所以不会阻塞渲染。
2. 进行样式计算,合成render树
主线程会遍历得到的DOM 树,结合
CSSOM树,去计算样式,计算过程中有些样式会变化,去得到每个元素的最终样式,称之为Computed Style。在这一过程中,很多预设值会变成绝对值,比如red会变成red(255,0,0),相对单位会变成绝对单位,比如em会变成px。

3. 布局
布局阶段会依次遍历
DOM树的每一个节点,计算每个节点的几何信息,例如节点的宽高、相对包含块的位置。大部分时候,DOM树和布局树并非一一对应。布局完成后会得到布局树。

Dom树和Layout树为什么不是一一对应的?
比如
display:none的节点没有任何信息,因此不会生成布局树;又比如使用了伪类选择器,虽然DOM树中不存在这些伪元素节点,但他们拥有几个信息,所以会生成到布局树中。还有匿名行盒和匿名块盒等待都会导致DOM树和布局树无法一一对应。


4. 分层:Layer
主线程会使用一套复杂的策略对整个布局树中进行分层,每个层面可以单独进行绘制。分层的好处在于,将来某个层次改变后,仅会对该层进行后续处理,从而提升效率。像滚动条、堆叠上下文、
transform、opacity z-index等样式可能会影响分层结果,也可以通过设置will-change 属性更大程度的影响分层结果.

will-change:transform
一定是效率出现了问题,调整后发现是分层导致的卡顿,不要滥用,这个样式会告诉浏览器可能会发生变化
5. 绘制
会先去生成绘制的指令集合,用于描述这一层的内容如何画出来,例如:先后顺序,位置确定等等。主线程任务会停止,然后交给其他线程来操作。

6. 分块
完成绘制后,主线程将每个图层的绘制信息提交给合成线程,剩余工作交给合成线程完成。合成线程首先将每个图层进行分块,将其划分为更多的小区域,分块会将每一层分为多个小的区域,将工作交给多个线程同时进行
它会从线程池中拿取多个线程来完成工作


7. 光栅化
合成线程会将块信息交给
GPU进程,以极高的速度完成光栅化,GPU进程会开启多个线程来完成光栅化,并且优先处理靠近视口区域的块。光栅化的结果,就是一块一块的位图


8. 画
最终画在浏览器屏幕上

三、和整个过程相关的一些扩展知识点:
1. 什么是浏览器的默认样式?
p div为什么独占一行,是因为浏览器给它设置了默认样式,display:block,所以它才独占一行,惊不惊喜,意不意外?原来这么简单
2. 什么是行盒?什么是块盒?
内容必须在行盒中,如果在p 元素中有一个元素,没有包行盒,那就会自动给它补充一个匿名行盒。已经早就没有行元素和块元素的说法了,因为元素的样式是由css来决定的而不是html的元素,行盒和块盒不能相邻。

3. 为什么要使用 http 缓存?
- 减少了冗余的数据传输,节省了网费。
- 缓解了服务器的压力, 大大提高了网站的性能
- 加快了客户端加载网页的速度
4. 为什么浏览器会有兼容性问题?
浏览器的兼容性?
源于浏览器的渲染引擎,渲染引擎决定了浏览器如何显示网页的内容以及页面的格式信息。不同的浏览器内核对网页编写语法的解析也有不同,因此同一网页在不同的内核的浏览器里的渲染(显示)效果也可能不同,这就出现了浏览器兼容性问题。
常见的浏览器内核:
-
Trident内核:IE、360、搜狗浏览器等。 -
Webkit内核:Safari、Chrome等。
扩展知识点:【 Chrome的Blink是WebKit的分支,V8是Blink的js引擎】
关于js兼容性问题的解决
使用
babel来转译,因为它是可以将最新版本的js 语法转为最老的js 语法,让更多的浏览器可以识别
关于css 兼容性问题的解决
在样式的头部加浏览器的前缀:例如
-webkit
关于html 兼容性问题:
可以通过设置
<!DOCTYPE html>字段来解决,如果不写,各个浏览器会使用自己的怪异模式去解析,不是我们想要的结果,写了是让浏览器用统一方式去处理
5. 什么是重排reflow?
reflow的本质就是重新计算layout树。当局部或者整体布局发生改变,例如:新增或者删除dom元素,改变margin、padding、 字体大小等等。可能会影响到布局时,就会启动重新计算样式,重新生成布局,重新排列元素。相当于从计算样式向后所有的步骤都要走一遍,所以会比较耗费性能。
为了避免连续的多次操作导致布局树反复计算,浏览器会合并这些操作,当js 代码全部完成后再进行统一计算。所以,改动属性造成的reflow是异步完成的。也同样因为如此,当js 获取布局属性时,就可能无法获取到最新的布局信息。浏览器为了避免这个情况的产生,读取样式会立即执行reflow

6. 什么是重绘 repaint?
repaint的本质就是重新根据分层信息计算了绘制指令。当某些元素的外观被改变,就需要重新计算。计算样式和绘制阶段之后的阶段都要重新过一遍。
重绘不一定导致重排,但重排一定会导致重绘。重排的开销要远远大于重绘,会破坏用户体验,并且让UI展示非常迟。所以我们要尽量减少页面重排次数。

7. 为什么transfrom 的效率高?
因为
transform改动样式后,就只影响了计算样式和最后画的步骤,中间很多步骤都可以跳过,所以它的效率要高。

如果transform来配合 animation一起使用,效率会更高,中间步骤直接都跳过,只影响最后画的步骤。

8. 浏览器遇到无法解析的css 会做什么?
9. 关于几种刷新后对缓存的影响?
地址栏回车:
浏览器发起请求,按照正常流程,本地检查是否过期,然后服务器检查新鲜度,最后返回内容。
点击刷新按钮或者按 F5:
浏览器直接对本地的缓存文件过期,但是会带上
If-Modifed-Since,If-None-Match,这就意味着服务器会对文件检查新鲜度,返回结果可能是304,也有可能是200。
用户按 Ctrl+F5强制刷新:
浏览器不仅会对本地文件过期,而且不会带上
If-Modifed-Since,If-None-Match,相当于之前从来没有请求过,返回结果是200。
10. 什么时候会断开TCP的连接
不同的协议断开的标准不同,但都是一定程度上避免浪费资源,因为保持连接对于服务器来说也是需要占用资源的
-
http1: 如果没有设置keep-alive,一个请求发送过去,服务端响应后,就会立即断开 -
http1.1内部自带keep-alive,短时间内是不用重复连接的,keep-alive会有一个过期时间,当超过设置时间会自动断开 -
http2是支持多路复用的,所以和请求否响应无关,它的断开标准通常是当双方服务器在30秒内如果没有再发生交互,即断开连接。

11. https和http有什么区别?
https不是http的对立面,两者在本质上是相同的,都采用相同的“超文本传输协议”,使请求的数据能够显示在网站上。
安全性:
http协议以明文方式发送内容,不提供任何方式的数据加密。http协议不适合传输一些敏感信息,比如:信用卡号、密码等支付信息。https则是具有安全性的SSL / TLS加密传输协议,可防止通过 Internet 发送的数据(用户名,银行卡密码等)被第三方拦截和读取。
连接方式:
http和https使用的是完全不同的连接方式,http 连接建立相对简单, TCP 三次握手之后便可进行 HTTP 的报文传输。而 https 在 TCP 三次握手之后,还需进行 SSL/TLS 的握手过程,才可进入加密报文传输。用的端口也不一样,前者是80,后者是443。
权威认证:
https 协议需要向 CA(证书权威机构)申请数字证书,来保证服务器的身份是可信的;http 则不需要。
总结:HTTPS相对复杂,拥有权威认证,也更安全,也是以后网站的普遍模式。HTTPS协议的主要作用可以分为两种:一种是建立一个信息安全通道,来保证数据传输的安全;另一种就是确认网站的真实性。
12. http中的Keep-Alive有了解吗?
Keep-Alive是http的一个头部字段Connection中的一个值,它是保证我们的http请求能建立一个持久连接。也就是说建立一次TCP连接即可进行多次请求和响应的交互。它的特点就是只要有一方没有明确提出断开连接,则保持TCP连接状态,减少TCP连接和断开造成的额外开销。
HTTP/1.0阶段:
在HTTP/1.0中所有的连接默认都是关闭的,如果客户端浏览器支持Keep-Alive,那么就在HTTP请求头中添加一个字段Connection: Keep-Alive,当服务器收到附带有Connection: Keep-Alive的请求时,它也会在响应头中添加一个同样的字段来使用Keep-Alive。这样一来,客户端和服务器之间的HTTP连接就会被保持,不会断开(超过Keep-Alive规定的时间,意外断电等情况除外),当客户端发送另外一个请求时,就使用这条已经建立的连接。
HTTP/1.1阶段
在HTTP/1.1中所有的连接默认都是持久连接的。除非在请求头或响应头中指明要关闭:Connection: Close,这也就是为什么Connection: Keep-Alive字段再没有意义的原因。目前大部分浏览器都是用http1.1协议,也就是说默认都会发起Keep-Alive的连接请求了。
HTTP/2阶段
多路复用:
- 可以并行交错地发送请求 / 响应,请求/响应之间互不影响,
- 只使用一个连接即可并行发送多个请求和响应;
13. HTTP/1.1 和HTTP/2 的区别?
- 二进制:
HTTP/1.1版本的头部信息是文本,数据部分可以是文本也可以是二进制。HTTP/2版本的头部和数据部分都是二进制,且统称为 帧; - 多路复用:废弃了
HTTP/1.1中的管道,同一个TCP连接里面,客户端和服务器可以同时发送多个请求和多个响应,并且不用按照顺序来。由于服务器不用按顺序来处理响应,在一定程度上提升了效率;
多路复用如下图:
-
头部压缩:
HTTP/1的header带有大量信息,而且每次都要重复发送;HTTP/2使用encoder来减少需要传输的header大小,通讯双方各自缓存 一份header信息字典表,既避免重复传输,又提升了传输速度。 -
服务器推送::
HTTP/2允许服务器未经请求,主动向客户端发送资源,这叫做服务器推送。使用服务器推送提前给客户端推送必要的资源,这样就可以相对减少一些延迟时间。(这里需要注意的是HTTP/2下服务器主动推送的是静态资源,和WebSocket以及使用SSE等方式向客户端发送即时数据的推送是不同的。)
14. 网络分层是 5 层还是 7 层?
OSI 七层参考模型:
物理层 -> 数据链路层 -> 网络层(Ip)-> 传输层(TCP)- > 会话层-> 表现层- > 应用层(http)顶层
我们所知道的还有 TCP/IP 四层模型和 TCP/IP 五层模型。这又是怎么出来的,其实所谓的 TCP/IP 四层模型和 TCP/IP 五层模型是以 OSI 七层优化而来,把某些层进行合并了(会话层,表现层,应用层合并成应用层),其实本质上还是相同的,。
互联网 5层协议模型:
物理层 -> 数据链路层 -> 网络层(Ip)-> 传输层(TCP)->应用层(http)
- 物理层:用物理手段将电脑连接起来,就像我们讲到的计算机之间的物理连线。主要用来传输
0、1信号,所有我们用另一层用来规定不同0、1组合的意义是什么。 - 数据链路层:在数据链路层规定一套协议,专门的给
0、1信号进行分组,以及规定不同的组代表什么意思,从而双方计算机都能够进行识别,这个协议就是"以太网协议" - 网络层:网络层的由来是因为在数据链路层中我们说说两台计算机之间的通信是分为同一子网络和不同子网络之间,那么问题就来了,怎么判断两台计算机是否在同一子网络(局域网)中?这就是网络层要解决的问题。
- 传输层:传输层的主要功能就是为了能够实现"端口到端口"的通信。计算机上运行的不同程序都会分配不同的端口,所以才能使得数据能够正确的传送给不同的应用程序。
- 应用层:应用层的功能就是规定了应用程序的数据格式。我们经常用得到的电子邮件、
HTTP协议、以及FTP数据的格式,就是在应用层定义的。
15. 什么是http缓存?
http缓存指的是: 当客户端向服务器请求资源时,会先抵达浏览器缓存,如果浏览器有要请求资源的副本,就可以直接从浏览器缓存中提取而不是从原始服务器中提取这个资源。
常见的http缓存只能缓存get请求响应的资源,对于其他类型的响应则无能为力,所以后续说的请求缓存都是指get请求
分类:
- 根据是否需要再请求:可分为强制缓存和协商缓存,强制缓存如果生效,不需要再和服务器发生交互,而协商缓存不管是否生效,都需要与服务端发生交互;
- 根据是否可以被单个或者多个用户使用来分类,可分为私有缓存和共享缓存
在协商缓存时,ETag的优先级是高于Last-Modifined,原因如下:
-
某些服务器不能精确得到文件的最后修改时间, 这样就无法通过最后修改时间来判断文件是否更新了。
-
某些文件的修改非常频繁,在秒以下的时间内进行修改. Last-Modified只能精确到秒。
-
一些文件的最后修改时间改变了,但是内容并未改变。 我们不希望客户端认为这个文件修改了。
关于缓存的细节如下图:
16. 都有哪些本地存储的方案?
本地缓存一般使用较多的有:
localStorage、 sessionStorage、 cookie、indexdb
区别:
- localStorage:
HTML5新特性,只要在相同的协议、相同的主机名、相同的端口下,就能读取/修改同一份localStorage数据,是永久存储,除非手动删除,大小5M左右,IE8以上,不能被爬虫抓取到 - sessionStorage:
HTML5新特性,比localStorage更严苛一点,除了协议、主机名、端口外,还要求在同一窗口,也就是浏览器的标签,仅仅是会话级别的存储,这些数据只有在同一个会话中的页面才能访问并且当会话结束后数据也随之销毁。 - cookie: 保存用户登录状态的数据会在每一次发送
http请求的时候,同时发送给服务器,而localStoage和sessionStorage不会,最小,最大4KB,可设置过期时间,默认当浏览器关闭进程的时候自动销毁。 - indexdb:
iE10以上,比较适合键值对较多的数据,如果数据结构比较复杂,同时对浏览器兼容性没什么要求,存储量最大50M。
17. 什么是websocket?
Websocket 是h5提供的一种在单个TCP连接上进行全双工通信的协议,只需要服务器和浏览器通过HTTP协议进行握手之后,两者之间就直接可以创建持久性的连接,可以双向发送或接收信息,并且允许服务器主动向客户端推送数据,适合数据需要及时刷新的场景。
websocket特性:
- 性能高,
http是基于文本,websocket是二进制; - 双向通信;
- 在建立连接时还需要
http来通信; - 天生支持跨域;
- 天然支持加密,安全;
- 如果断开会自动重连。
websocket 封装库 socket.io
我们知道原生的
websocket写起来是非常费脑细胞的,所以推荐一个库,socket.io,使用起来较为方便,并且它支持ie5,而且是跨域自动解析数据,非常非常推荐!!!!
18. websocket与http有什么区别?
相同点:
- 都是一样基于
TCP的,都是可靠性传输协议。 - 都是应用层协议。
区别:
WebSocket是双向通信协议,可以双向发送或接收信息;而HTTP是单向的,只能由客户端发起请求到服务端去请求数据,服务端只能作为被动方;http是短连接,请求之后都会关闭连接,下次请求需要重新打开连接;websocket是长连接,只需要通过一次请求来初始化连接,后面就可以进行双向数据通信
WebSocket连接的过程:
- 客户端发起
http请求,经过3次握手后,建立起TCP连接; http请求里存放WebSocket支持的版本号等信息,如:Upgrade、Connection、WebSocket-Version等;- 服务器收到客户端的握手请求后,同样采用
http协议回馈数据; - 客户端收到连接成功的消息后,开始借助于
TCP传输信道进行全双工通信。
本期先分享到这里,后面有浏览器相关的内容我会再做补充,欢迎各位掘友收藏关注哈!!!
转载自:https://juejin.cn/post/7240333779221987384
