对减少HTTP请求的疑问

教条

根据各种Web性能优化手册,减少HTTP请求这一条始终被放在显眼的位置,其中就包括著名的YSlowGoogle Page Speed,两者对这一教条的解释分别是:

80% of the end-user response time is spent on the front-end. Most of this time is tied up in downloading all the components in the page: images, stylesheets, scripts, Flash, etc.

YSlow表示,前端的多数时间是用在下载图片、样式表、脚本、Flash等,所以要减少HTTP请求。

RTT is the major contributing factor to latency on "fast" (broadband) connections.

Page Speed则表示,RTT(请求往返时间)是导致连接快不起来的主要原因,所以要减少,即减少HTTP的请求数。

疑惑

很少人会对这2大优化守则产生怀疑,因为它们即真理、即教条、即必须遵守之则,如有违逆,虽远必诛……

但是如果认真地去解读这2条规则,其他他们都表达了一个意思:网络上的往返越多,响应的速度就越慢。

但是他们却忽略了一个很重要的事情,那就是工作总用时多,并不代表任务完成时间也多,因为这里有一个概念,叫作并行。

试想一个任务,用一个线程跑,和用100个线程跑,哪一个总用时更少?答案其实是一个线程,因为100个线程之间有线程切换的开销、有结果join的时间、有任务分割的时间……但是从结论上来看,哪一个能更快地跑完任务?答案是多线程,这就是并行计算的理论来源。

事实上,资源的下载也是如此,如果并行的话,多个资源的下载时间不见得会小于一个资源,如下图是一个合并后的资源的下载示意:

大资源下载示意

上图用来表示一个较大的资源的下载过程,其中不同的颜色分别对应:

  • 蓝色:TCP链接建立时间
  • 绿色:请求头发送时间
  • 紫色:服务器处理时间
  • 橙色:响应头发送时间
  • 红色:文件传输时间
  • 灰色:文件解析执行时间

如果将这个大资源分解成3个相等的小资源的话,那么他们的下载就可能是这样的:

小资源下载示意

由于浏览器只有一个线程可以对文件进行解析和执行,因此灰色的解析部分必定是串行的,需要相互等待。

比较2张图,假设其中的每一小块的时间为t,可以发现这样一个结论:一个大资源的加载,使用了13t的时间,而将大资源分解后,虽然总共用了21t的时间,但是客户端真正等待的时间却只有9t,比合并资源的方式节约了4t。

这就是并行的效果,当然要实现这个效果,是有前提的:

  • 并行的连接数没有超过浏览器的限制,这里假设4并行是一个比较合理地、照顾到各浏览器的值。
  • 服务器能顶得住,不会因为并发连接过多而导致处理时间变长。
  • 网络足够稳定,这一点将保证TCP建立、请求头发送、响应头发送这3段时间是稳定的。
  • 浏览器的资源加载不会阻塞,如IE6-7在下载js文件时会阻塞后续资源的请求,则不可能实现并行。

缓存的考虑

合并资源有另一个好处,就是在缓存之后,只需向服务器验证一次即可。但是再和拆分资源的加载过程作一个比较,如果采用带验证的缓存,不难得出下图:

服务器缓存的情况

而如果使用客户端的缓存,则是以下情况:

客户端缓存的情况

从上面2张图中可以看到,即便在有缓存的情况下,如果满足一定的条件,可以进行并发的话,若干个小资源的加载情况下客户端的等待时间和合并为一个大资源后是相同的,并没有多余的消耗。

总结

一个最基础的结论是,加载资源总用时和客户端等待时间是2个完全不同的概念,他们之间并不存在正比的关系,而在宽带普及的当前时代,多数网络资源并不是按流量收费的,因此前端的优化应该更关注于客户端等待时间,而不是加载资源总用时和流量之上。

事实上,一个最经典的应用就是下载软件,从90年代的NetAnt开始,到其后的网际快车、迅雷,无一不具有多线程下载的能力。事实上多线程下载同样会因为线程的切换、文件分段的空间分配、最后多段碎片的拼接等导致总耗时更多,但也确确实实极大地缩短了下载的时间。在对页面的资源加载作优化时,是不是也可以参考一下这个模型呢?

由此,对资源的切分将会从单纯的“合并”的级别,提升到一种完全艺术的程度,综合考虑不同浏览器对资源加载的策略,最大限度利用浏览器的并行下载能力,从而正确、最优地分配静态资源域名,切分静态资源,压榨浏览器全部的能力,进一步地提升页面加载的速率。这虽然大大提高了资源管理、分解的复杂度,但是对于追求极限而言,本人认为这样才是真正的最佳实践。

最后,本文完全没有全部否定减少HTTP请求数这一优化原则的意思,只是希望从另外一个角度看问题,保持着一定的怀疑的心态来重新审视这一原则,拒绝不经过思考的无意义的遵循,从而寻找到在特定环境下,最适合、最优化的方案。

补充一点,事实上HTTP基于TCP大家都知道,而TCP有一个叫做速度协商的过程,因此TCP的传输速度一开始的时候是不会快的,一定时间后才能达到满带宽的状态。因此对于本身不大,在速度协商过程中就传输完了的资源来说,分块下载是非常糟糕的一种方式。简而言之,一个资源是否拆分,和这个资源的大小有很大的关联,依据实际场景而定。