主要几个过程:
1. DNS域名解析
2. 建立起TCP连接,三次握手
3. 发起HTTP请求
4. 服务器响应请求,浏览器获取到内容
5. 解析页面流程
6. 回流与重绘
7. JS引擎解析
8. 断开连接,四次挥手
一、 DNS域名解析
- 浏览器首先检查缓存中有没有这个域名对应解析过的IP地址,如果有,解析就会结束。(缓存时间不长,大概一分钟,容纳1000条缓存)
- 检查操作系统缓存中是否有这个域名对响应的DNS解析结果
- 读取本地的一个hosts文件,查找域名对应解析过的IP地址
- 如果依旧没有找到,就会向本地服务器查询(LDNS),比如你是小区上网,那么这个本地服务器一般都是网络提供商,比如电信的DNS服务器
- 接下来就是根域名服务器解析。返回给本地服务器一个所查询的主域名服务器,比如是.com .cn .org
- 本地服务器再向上一步返回来的主域名服务器发送请求
- 接收请求的顶级域名服务器返回这个域名对应的一个权威服务器(Name Server),就是你注册的一个域名服务器,例如用户在某个域名服务提供商申请的域名
- 权威服务器查询存储的域名和IP的映射关系表,然后将IP连同一个TTL值返回给域名服务器
- 本地服务器拿到这个IP和TTL缓存起来,缓存时间是TTL控制
- 最后返回解析结果给用户。用户根据TTL值缓存在本地系统中,域名解析结束
浏览器缓存 --> 操作系统缓存 --> hosts文件 --> 根域名服务器
二、建立TCP连接,三次握手
- 客户端首先发送一个连接试探(ACK=0表示确认号无效,SYN=1表示是一个连接请求或者接受报文,seq=x表示客户端初始序号包)
- 服务端监听到请求报文后,同意建立连接,向客户端发送请求
- 客户端收到确认后还需要再次发送确认,并且携带要发送给服务器的数据
三次握手是为了防止出现失效的连接请求报文被服务端接收的情况。第一次握手是不会携带数据的
比如:客户端发送一个连接请求A,但突然因为网络原因造成超时,TCP就会启动超时重传机制再次发送一个连接请求B,请求顺利到达了服务端。服务端接收数据之后释放连接。但是假如这个时候连接请求A在两端关闭后抵达了服务器,服务器就会答应请求,一直等待,造成资源的浪费
而为什么不能两次握手,是因为这样服务端只是怼客户端做了确认,客户端并没有做确认,并不能保证传输。而四五次以上就会造成一个资源的浪费
通俗化就是:
客户端:老哥,在吗,有你的信
服务端:在的,送过来就行
客户端:好的
三、发起HTTP请求
与服务器建立连接后,就可以发起请求。请求报文中包括请求行、请求头、空行、请求主体。http默认端口是80,https是443
http和https区别
- https协议需要ca申请证书,免费证书较少,需要一定费用
- http是明文传输,https是具有安全性的ssl加密传输协议
- http和https使用不同的连接方式,端口也不同
四、服务器响应请求
HTTP响应由三个部分组成,分别:状态行、消息报头、响应体
- 1xx:信息性(接收的请求正在处理)
- 2xx:成功请求
- 3xx:重定向(需要进一步操作完成请求)
- 4xx:客户端错误
- 5xx:服务端错误
五、解析页面流程
-
html解析,构建DOM树
Bytes --> characters --> tokens --> nodes --> DOM 1. 浏览器将获得的Bytes基于编码转换成html代码(解码) 2. 浏览器根据html规范将字符转换不同的token 3. 将一堆token转换成对象,对象分别定义属性和规则 4. DOM构建
-
CSS解析,构建CSS规则树
CSS解析,选择器是从右向左解析如果从左到右匹配,发现不符合规则的时候会回溯,损失性能。而从右向左匹配,从第一步就筛选掉大量不符合的子节点。
-
合并DOM树和CSS规则树,生成render树
-
布局render树,负责各个元素的尺寸,位置计算
-
绘制render树,绘制页面像素信息
-
浏览器将各层的信息发送给GPU,GPU将各层合并显示在屏幕上
HTML --> HTML Parser --> DOM Tree Style Sheets --> CSS Parser --> Style Tree DOM Tree + Style Tree --> Render Tree Layout(Render Tree) --> Painting --> Display
六、重绘与回流
重绘:元素发生的改变只是影响元素的一些外观
回流:元素的内容、结构、位置、尺寸发生改变,需要重新计算样式,回流是一定伴随重绘,但是重绘是单独出现的
以下行为都会触发到回流:
- 页面渲染初始化
- DOM结构变化,比如增加删除节点
- render树变化,比如增加减少padding
- 窗口的resize
- 获取一些属性(offset,scroll,client,width,height,getComputedStyle())
- 改变字体的大小
优化回流:
-
减少逐项去修改样式
-
避免循环操作DOM
-
谨慎使用table布局,因为一个小改动就会造成整个table的重新布局
-
使用visibility代替display:none,前者只会引起重绘,后者会引发回流
var s = document.body.styles.padding = "10px" // 回流+重绘 s.border = "1px solid red" // 回流+重绘 s.color = 'red' // 重绘 s.backgroundColor = "blue" // 重绘 s.fontSize ="20px" // 回流+重绘 document.body.appendChild(document.createTextNode('a')) // 添加node,回流+重绘
七、JS引擎解析
- 浏览器首次加载脚本,创建全局上下文,并压入栈顶
- 每进入其他作用域就创建对应的执行上下文并把它压入执行栈
- 一旦对应的上下文执行完成,就从栈顶弹出
八、断开连接,四次挥手
- 客户端发送断开连接请求
- 服务端接收请求,发回一个确认
- 服务端向客户端发送结束,服务端关闭客户端的连接
- 客户端向服务端发送确认,服务端收到后关闭,客户端等待一段时间也进行关闭状态
四次挥手是为了:服务端收到客户端的关闭连接请求,不会立即关闭连接。需要等待所有数据传输完毕后才关闭。所以先回复客户收到了报文,数据传输完毕才告诉客户端可以进行关闭。客户端回复报文进行确认,这才算是真正的关闭了。
通俗化就是:
客户端:大哥,我们关闭连接叭
服务端:好,收到了
服务端:我这也没啥要传输的,关了哦
客户端:OK