1、浏览器的地址栏输入URL并按下回车。
1、解析URL,判断url是否合法,然后浏览器查找当前URL是否存在缓存,并比较缓存是否过期。
2、DNS解析URL对应的IP。
3、根据IP建立TCP连接(三次握手)。
4、HTTP发起请求。
5、服务器处理请求,浏览器接收HTTP响应。
6、渲染页面,构建DOM树。
7、关闭TCP连接(四次挥手)。
首先会对 URL 进行解析,分析所需要使用的传输协议和请求的资源的路径。如果输入的 URL 中的协议或者主机名不合法,将会把地址栏中输入的内容传递给搜索引擎。如果没有问题,浏览器会检查 URL 中是否出现了非法字符,如果存在非法字符,则对非法字符进行转义后再进行下一过程。
假设输入的URL是包含域名的,那肯定会涉及到DNS解析。当然,如果URL仅仅是IP,那就不会涉及到DNS的。域名的出现是为了方便记忆,因为域名比IP好记。我们这里假设URL包含域名。DNS域名解析,采用的是递归查询的方式,
浏览器缓存
首先会在自己的浏览器缓存中查找是否有该域名对应的IP地址(若曾经访问过该域名且没有清空缓存便存在);
系统缓存
当浏览器缓存中无域名对应IP则会自动检查用户计算机系统Hosts文件DNS缓存是否有该域名对应IP;
但是这种操作系统级别的域名解析规程也被很多黑客利用,通过修改你的hosts文件里的内容把特定的域名解析到他指定的ip地址上,造成所谓的域名劫持。所以在windows7中将hosts文件设置成了readonly,防止被恶意篡改。
路由器缓存
当浏览器及系统缓存中均找不到时则进入路由器缓存中检查,以上三步均为客服端的DNS缓存;
ISP(互联网服务提供商)DNS缓存
当在用户客服端查找不到域名对应IP地址,则将进入ISP DNS缓存中进行查询。比如你用的是电信的网络,则会进入电信的DNS缓存服务器中进行查找;
当以上均未完成,则进入dns域名服务器查询
最后再将找到的ip返回给用户,并将其缓存在本地,方便下次使用
而且,需要知道DNS的解析时很耗时的,因此,如果解析域名过多的话,会让首屏加载速度变得很慢(一个优化首批速度的点),可以考虑一下dns-prefetch优化
TCP是可靠的面向链接的协议
所谓三次握手(Three-way Handshake),是指建立一个 TCP 连接时,需要客户端和服务器总共发送3个包。
三次握手的目的是连接服务器指定端口,建立 TCP 连接,并同步连接双方的序列号和确认号,交换 TCP 窗口大小信息。在 socket 编程中,客户端执行 connect() 时。将触发三次握手。
第一次握手 客户端发送一个 TCP 的 SYN=1(synchronous建立联机)的包,指明客户端打算连接的服务器的端口,随机产生seq number=1234567的数据包到服务器,发送完毕后,客户端进入 SYN_SEND 状态。
第二次握手:服务器收到请求后要确认联机信息,向A发送syn=1,ack=1(acknowledgement 确认),ack number=(主机A的seq+1),随机产生seq=7654321的包;发送完毕后服务器端进入 SYN_RCVD 状态
第三次握手客户端收到后检查ack number是否正确,即第一次发送的seq number+1,以及位码ack是否为1,若正确,主机A会再发送ack number=(主机B的seq+1),ack=1,主机B收到后确认seq值与ack=1则连接建立成功。
客户端发送完毕后,会进入 ESTABLISHED 状态,当服务器端接收到这个包确认后,也进入 ESTABLISHED状态,TCP 握手结束。
待到断开连接时,就需要进行四次挥手。因为时全双工的,何为全双工就是客户端与服务端建立两条通道,因此每个方向都必须单独进行关闭,客户端或服务器均可主动发起挥手动作,在 socket 编程中,任何一方执行 close() 操作即可产生挥手操作。
TCP四次挥手
第一次挥手(FIN=1,seq=x):假设客户端想要关闭连接,客户端发送一个 FIN=1的包,表示自己已经没有数据可以发送了,但是仍然可以接受数据。发送完毕后,客户端进入 FIN_WAIT_1 状态。
第二次挥手(ACK=1,ACKnum=x+1):服务器端确认客户端的 FIN 包,发送一个确认包,表明自己接受到了客户端关闭连接的请求,但还没有准备好关闭连接。 发送完毕后,服务器端进入 CLOSE_WAIT
状态,客户端接收到这个确认包之后,进入 FIN_WAIT_2 状态,等待服务器端关闭连接。
第三次挥手(FIN=1,seq=y): 服务器端准备好关闭连接时,向客户端发送结束连接请求,FIN 置为1。 发送完毕后,服务器端进入LAST_ACK 状态,等待来自客户端的最后一个ACK。
第四次挥手(ACK=1,ACKnum=y+1):客户端接收到来自服务器端的关闭请求,发送一个确认包,并进入 TIME_WAIT状态,等待可能出现的要求重传的 ACK 包。服务器端接收到这个确认包之后,关闭连接,进入 CLOSED 状态。 客户端等待了某个固定时间(两个最大段生命周期,2MSL,2 Maximum Segment Lifetime)之后,没有收到服务器端的 ACK ,认为服务器端已经正常关闭连接,于是自己也关闭连接,进入CLOSED 状态。
完整的HTTP请求包含请求起始行、请求头部、请求主体三部分。
服务器在收到浏览器发送的HTTP请求之后,会将收到的HTTP报文封装成HTTP的Request对象,并通过不同的Web服务器进行处理,处理完的结果以HTTP的Response对象返回,主要包括状态码,响应头,响应报文三个部分。
状态码主要包括以下部分
1xx:指示信息–表示请求已接收,继续处理。
2xx:成功–表示请求已被成功接收、理解、接受。
3xx:重定向–要完成请求必须进行更进一步的操作。
4xx:客户端错误–请求有语法错误或请求无法实现。
5xx:服务器端错误–服务器未能实现合法的请求。
响应头主要由Cache-Control、 Connection、Date、Pragma等组成。
响应体为服务器返回给浏览器的信息,主要由HTML,css,js,图片文件组成。
解析下载js、css、图片
1.解析html标签创建DOM树
2.解析css创建CSSOM树
3.将DOM和CSSOM合并生成reander树
4.布局reader树,计算各个节点的位置与大小
5.渲染,呈现页面
在这一过程中可能会触发页面的重绘或重排。这里就涉及了两个重要概念:Reflow和Repaint。
Reflow,也称作Layout,中文叫回流,一般意味着元素的内容、结构、位置或尺寸发生了变化,需要重新计算样式和渲染树,这个过程称为Reflow。
Repaint,重绘,意味着元素发生的改变只是影响了元素的一些外观之类的时候(例如,背景色,边框颜色,文字颜色等)
重绘回流的代价是会导致卡慢,不过浏览器有自己的优化,它会维护一个队列,把所有引发重绘回流的操作都放入这个队列中,等队列到了一定的数量或者是到了一定的时间,浏览器会flush队列,进行一次批处理,这样子就会让多次的重绘回流,变成一次重绘回流了
优化:
let fragment = document.createDocumentFragment() //创建一个虚拟节点
for(let i=0;i<99999;i++){
let li = document.createElement('li')
li.innerHTML = 'li'+i;
fragment.appendChild(li)
}
document.getElementById('ul').appendChild(fragment) //集中在一次性添加
TCP四次挥手关闭TCP链接