第一步:在浏览器输入 URL
第二步:查看缓存
- 浏览器缓存
- 查找顺序:Service Worker → Memory Cache → Disk Cache → Push Cache
- Service Worker
- 运行在浏览器背后的独立线程
- 传输协议必须为 HTTPS,因为 Service Worker 中涉及到请求拦截,使用 HTTPS 协议来保障安全
- Memory Cache
- 读取速度快,缓存时间短,关闭 Tab 后就释放
- 内存中的缓存,包含当前中页面中已经抓取到的资源
- Disk Cache
- 硬盘中的缓存
- 读取速度慢,但存储内容多,绝大部分的缓存都来自 Disk Cache
- Push Cache
- HTTP/2 中的内容
- 只在 Session 中,会话结束被释放,缓存时间短
- Service Worker
- 查找顺序:Service Worker → Memory Cache → Disk Cache → Push Cache
- 系统缓存:通过系统调用获得系统缓存中的记录(windows里是gethostbyname)
- 路由器缓存:一般会有自己的DNS缓存
- ISP DNS 缓存:从跟域名服务器开始进行递归搜索,从.com顶级域名服务器到Facebook的域名服务器。一般DNS服务器的缓存中会有.com域名服务器中的域名
第三步:DNS 域名解析
- DNS:Domain Name System域名系统,万维网上作为域名和IP地址相互映射的一个分布式数据库
- 如果没有访问过该url,就会进行DNS域名解析
- IP 和 域名一一对应
- DNS 解析过程
- 用户主机上运行着DNS的客户端
- 浏览器抽取 url 中的域名,传输给 DNS 客户端
- DNS 客户端向 DNS 服务器端发送一份查询报文
- 客户端接受返回报文,包含域名对应 ip
- 浏览器通过 ip ,向 IP 地址定位的 HTTP 服务器发起 TCP 连接
第四步:获取端口号
第五步:建立 TCP 连接
- 三次握手好朋友( TCP 连接过程)
- 服务端通过 socket,bind 和 listen 准备接受外来连接,此时服务端状态 Listen
- 客户端调用 connect 发起主动连接,向客户端 TCP 发送一个 SYN (同步)字节,告诉服务端客户将在(待建立的)连接中发送的数据的初始序列号,客户端状态为SYN_SENT
- 服务端确认(ACK)客户的 SYN,同时发送一个 SYN,包含服务端将在同一连接中发送数据的初始序列号
- 客户端确认服务的 ACK 和 SYN,向服务器发送 ACK,客户端状态 ESTABLISHED
- 服务器接收 ACK,服务器状态 ESABLISHED
第六步:HTTP 请求
- 应用层 -> 传输层 -> 网络层 -> 链路层
- 浏览器会向Web服务器以 Stream(流) 形式传输数据
- 服务器解析数据,读取 Web 资源内容,以流形式再返回给浏览器
第七步:关闭 TCP
- 四次挥手是路人
- 某端调用 close 成为主动关闭端,向另一端发送 FIN 分节,表示数据发送完毕,此时主动关闭端状态FIN_WAIT_1
- 接收到 FIN 的被动关闭端,FIN 由 TCP 确认,先向主动关闭端发送 ACK,作为一个文件结束符传递给接收端应用进程(放在已排队等候该应用进程接收到的任何其他数据之后),因为FIN的接收意味着接收端应用进程在相应连接无额外数据可接收,接收端状态 CLOSE_WAIT;主动关闭端接收到 ACK 状态变为 FIN_WAIT_2
- 一段时间后,接收端接收到这个文件结束符的应用进程调用 close 关闭套接字,向主动关闭端发送 FIN,接收端状态为 LAST_ACK
- 主动关闭端确认 FIN,状态变为 TIME_WAIT,并向接收端发送 ACK,接收端接收到 ACK 关闭 TCP,而主动关闭端一段时间后也关闭 TCP
第八步:浏览器渲染
- HTML 解析成一个DOM树。深度遍历:当前节点的所有子节点都构建好后才构建当前节点的下一个兄弟节点
- CSS 解析成 CSS Rule Tree
- 根据 DOM 树和 CSSOM 来构造 Rendering Tree
- Rendering Tree != DOM 树,因为像 Header 或 display:none 没必要放在渲染树
- Layout:根据 Rendering Tree 计算出每个节点在屏幕中的位置
- 绘制:遍历 Rendering Tree,使用 UI 后端层绘制每个节点