理解Chrome请求流程
Timing Tab
Chrome的DevTools中提供了对请求的时间分析,如配图所示。
对每个请求,Chrome统计了它们不同阶段的通信时间,包括:
- Queueing
- Stalled
- DNS Lookup
- Proxy negotiation
- Initial Connection /Connecting
- SSL
- Request sent
- ServiceWorker Preparation
- Request to ServiceWorker
- Waiting(TTFB)
- Content Download
- Receiving Push
- Reading Push
Queueing
Queueing意味着请求没有马上发生,加入队列排队等候。导致这种情况一般可能的原因有:
- 有更高优先级的请求
- 请求等待即将被释放的TCP socket
- 与当前域名的TCP连接数已满上限6个(仅对HTTP/1.0和HTTP/1.1生效)
- 浏览器正在分配磁盘缓存(一般非常短暂)
要注意的是第三点中的6个TCP连接数上限在不同浏览器中也不相同,根据HTTP协议的规定限制数量应为2个,但是各浏览器有不同的标准:
| Browser | Maximum connections |
|---------|---------------------|
| IE7 | 2 |
| IE8/IE9 | 6 |
| IE10 | 8 |
| IE11 | 13 |
| FireFox | 6 |
| Chrome | 6 |
| Safari | 6 |
| Opera | 6 |
| iOS | 6 |
| Android | 6 |
---------------------------------
Stalled
当请求被放入队列后,就会有阻塞的时长。Stalled描述的是请求被发送之前等待的时长,一般就是Queueing中的原因导致的。除此之外,Stalled还包含了代理协商的时长。
DNS Lookup
进行DNS查找(域名解析)的时长。每次请求一个新的域名的时候,需要进行一次完整的域名解析过程。
Proxy negotiation
浏览器与代理服务器进行协商的过程。
Initial Connection /Connecting
建立连接的时长,包括TCP握手/重试的时长和SSL协商的时长。
SSL
完成SSL握手的时长。
Request sending/sent
发布请求的过程时间,一般非常快。
ServiceWorker Preparation
浏览器启动Service Worker的时长。
Request to ServiceWorker
请求被发送至Service Worker的时长。
Waiting(TTFB)
等待最初相应的时长,A.K.A Time To First Byte。这个时长等于请求发送至服务器的延迟、响应返回至客户端的延迟、服务器处理请求的时间之和。
Content Download
浏览器接收完整相应的时长。
Receiving Push
浏览器接收服务器(HTTP/2)推送数据的时长。
Reading Push
浏览器读取接收到数据的时长。
结合上图为例,可以看到请求图中接口的时间消耗:
- 请求放入队列花费1.94ms
- 请求在队列中被阻塞了2.25ms直至开始发送请求
- 域名解析花费0.41ms
- 与服务器建立连接,花费72.11ms,其中,完成SSL协商,花费的38.24ms是包含在72.11ms内的
- 发送请求,花费0.17ms
- 发送后到接收第一个响应数据间隔了36.07ms
- 完成响应报文的下载花费了2.00ms
本次请求一共花了115.16ms(数据求和为114.95ms,推断各阶段间有细微执行时间没有统计到)。
Full Request Process
现在结合Chrome的DevTools信息,再来更新一下从请求到页面展示的流程,以用户在浏览器中输入www.baidu.com为例,其中Chrome相关内容加粗显示:
- 请求准备部分
- 用户在浏览器中输入www.baidu.com,按下回车
- Chrome开始准备请求,如果满足被Queued规则的话放入队列中等待
- 此时Chrome会分配磁盘的缓存空间为后续缓存操作做准备
- 队列任务等待结束,开始准备发送请求;非队列任务准备发送请求
- Chrome查询是否有可用的磁盘或内存缓存:
- 如有且新鲜,则获取缓存内容,跳过解析和发起请求过程
- 如果没有缓存,继续按照后续步骤发起请求
- 域名解析部分
- 浏览器解析URL,获取协议、路径和端口号
- 浏览器组装一个HTTP请求报文
- 浏览器进行域名解析,获取主机的IP地址,主要通过:
- 浏览器对域名解析结果的缓存
- 本机对域名解析结果的缓存
- hosts文件
- 路由器缓存
- ISP DNS缓存
- DNS递归查询
- 发起请求部分
- 获取到IP后打开一个socket,与目标建立TCP连接,进行三次握手,细节太多受限篇幅不在此叙述,花费时间即为Initial Connection中减去SSL相关的部分
- 如果为HTTPS请求,进行SSL握手,花费时间为Timing中SSL部分
- 发送HTTP请求
- 接收响应部分
- 服务器检查HTTP请求头是否包含缓存验证信息:
- 验证缓存新鲜,返回304
- 验证不通过,处理请求并准备HTTP相应
- HTTP响应通过建立的TCP连接发送给浏览器,首个报文抵达时间即为Waiting(TTFB),完整接收时长为Waiting+Content Download时长
- 浏览器视情况保留TCP连接或进行四次挥手结束连接
- 浏览器根据响应状态码进行处理
- 如果响应资源可以缓存,进行缓存
- 对压缩(如gzip)的响应进行解码
- 服务器检查HTTP请求头是否包含缓存验证信息:
- 处理响应资源,假设资源为HTML文档(后续过程可能没有严格的先后顺序):
- 构建DOM树
- 针对构建过程中遇到的图片、样式、js启动下载
- 构建CSSOM树
- 根据DOM树和CSSOM树构建渲染树
- JS解析
- 显示页面
Ref
chromium.org – Issue: Match Firefox’s per-host connection limit of 15