很多人都说要减少http请求,可关注为什么要减少请求的人却少很多,本文是对我在几篇博客以及知乎上看到的内容的整理。
http请求头的数据量
每次请求都会带上一些额外的信息进行传输,当请求的资源很小,比如1个不到1k的图标,可能request带的数据比实际图标的数据量还大。 所以当请求越多的时候,在网络上传输的数据自然就多,传输速度自然就慢了。 其实request自带的数据量还是小问题,毕竟request能带的数据量还是有限的。
http连接的开销
相比request头部多余的数据,http连接的开销则更加严重。先看看从用户输入1个URL到下载内容到客户端需要经过哪些阶段: 1. 域名解析 2. 开启TCP连接 3. 发送请求 4. 等待(主要包括网络延迟和服务器处理时间) 5. 下载资源 6. 文件解析执行时间 其实,每次请求花费的大部分时间在其他阶段,而不是在下载资源阶段 ,再小的资源照样会花费很多时间在其他阶段,只是下载阶段会比较短。
事情到这里还没完,网上看到有人提出了这样的疑问: 在http1.1,keep-alive是默认的,而且现代浏览器都有DNS缓存,那么对于“100条请求”和“对100条请求合并为1条请求”这两种方案来说: * DNS寻址由于有DNS缓存–无差别; * 3次握手由于有keep-alive,一条和一百条都只需一次TCP握手–无差别; * 服务器解析–无差别; 只是增多了http报文头,在实际应用中,是否有大的性能差别?
答案是否定的。
即使有DNS缓存,浏览器也需要查找缓存,多个请求就需要查找多次,而且缓存有可能被无故清空,这样多个请求的DNS查询有可能花费更多时间。
TCP握手时间确实没差别,但时间性能上差别非常大。HTTP1.1协议规定请求只能串行发送,这也是HTTP性能最差和最让人诟病的地方,也就是说一百个请求必须依次逐个发送。第80个请求必须依赖于第79个请求正常返回之后才能发送。这样就平白无故多出了99个网络RTT(网络延迟)。合并请求比keep-alive下不合并请求理论上能节省大概 RTT * (N - 1) 的加载时间。由此可见,网络延迟其实是在有keep-alive情况下仍然需要请求合并的主要动力。
head of line blocking(队头阻塞)。设想这样一个场景,一个页面有100个请求,第99个请求时,TCP丢了一个包,TCP自然会重传,重传时间是T1,重传成功后,浏览器才能获取到完整页面的响应内容,然后渲染和展示整个页面。也就是说整个页面的加载时间延迟了T1时间。在此之前,用户没有得到任何内容。但如果建立了100个TCP连接呢?第99个请求出现丢包,那也只影响了第99个资源的展现,前面接收到的98个资源依然能正常加载,不会导致整个页面无法加载。
浏览器通过一个TCP连接发送100个请求的事情根本就不可能发生。当你有100个资源时,这100个资源在浏览器看来是“同时都要”,而浏览器并没有什么智商去判断应该用1个链接解决这100个资源,还是用100个链接来解决,不然浏览器永远都只有一个TCP链接了。因此浏览器的静态的策略是在自己可承受的范围内尽可能地用多的链接来解决,大部分浏览器似乎是6-8个链接,这就导致握手也是6-8次。
所以,我们要理解合并请求是为了什么?减少了哪些时间?优化了哪些策略?权衡了什么利弊?合并请求并不是万能的。