這里的合並主要針對當前頁面上訪問的資源文件,比如css,js,圖片等。
HTTP請求過程
一個HTTP請求的主要過程是:
DNS解析(T1) -> 建立TCP連接(T2) -> 發送請求(T3) -> 等待服務器返回首字節(TTFB)(T4) -> 接收數據(T5)。
如下圖所示,是Chrome Devtools中顯示的一個HTTP請求,顯示了HTTP請求的主要階段,注意,Queueing階段是請求在瀏覽器隊列中的排隊時間,並不計入HTTP請求時間。
從這個過程中,可以看出如果合並N個HTTP請求為1個,可以節省(N-1)* (T1+T2+T3+T4) 的時間。
實驗論證
我們來做4組實驗,對比一個HTTP請求加載合並后的資源所需時間,和多個HTTP請求並行加載拆分的資源所需時間。每組實驗所用資源的體積大小有顯著差異。
實驗環境:
服務器:阿里雲ECS 1核 2GB內存 帶寬1M
Web服務器:Nginx (未啟用Gzip)
Chrome v66 隱身模式,禁用緩存
Client 網絡:wifi 帶寬20M
實驗 1
// parallel-large.html <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Parallel Large</title> <link rel="stylesheet" type="text/css" media="screen" href="large1.css" /> <link rel="stylesheet" type="text/css" media="screen" href="large2.css" /> <link rel="stylesheet" type="text/css" media="screen" href="large3.css" /> <link rel="stylesheet" type="text/css" media="screen" href="large4.css" /> <link rel="stylesheet" type="text/css" media="screen" href="large5.css" /> <link rel="stylesheet" type="text/css" media="screen" href="large6.css" /> </head> <body> Hello, world! </body> </html>
// combined-large.html <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Combined Large</title> <link rel="stylesheet" type="text/css" media="screen" href="large-6in1.css" /> </head> <body> Hello, world! </body> </html>
分別刷新2個頁面各10次,利用Devtools 的Network計算CSS資源加載的平均時間。
注意事項:
- large1.css、large2.css … large6.css的加載時間,計算方式為從第一個資源的HTTP請求發送開始,到6個文件都下載完成的時間,如圖2紅色框內的時間。
- 兩個html頁面不能同時加載,否則帶寬為兩個頁面所共享,會影響測試結果。需要等待一個頁面加載完畢后,再手動刷新加載另外一個頁面。
- 頁面兩次刷新時間間隔在1分鍾以上 ,以避免HTTP 1.1 連接復用對實驗的影響。
實驗結果如下:
large-6in1.css | large1.css、large2.css … large6.css | |
---|---|---|
平均時間(s) | 5.52 | 5.3 |
我們再把large1.css、large2.css … large6.css合並為3個資源large-2in1a.css、large-2in1b.css、large-2in1c.css,每個資源282K,在combined-large-1.html中引用這3個資源:
// combined-large-1.html <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Parallel Large 1</title> <link rel="stylesheet" type="text/css" media="screen" href="large-2in1a.css" /> <link rel="stylesheet" type="text/css" media="screen" href="large-2in1b.css" /> <link rel="stylesheet" type="text/css" media="screen" href="large-2in1c.css" /> </head> <body> Hello, world! </body> </html>
測試10次,平均加載時間為5.20s。
匯總實驗結果如下:
large-6in1.css | large1.css、large2.css … large6.css | large-2in1a.css、... large-2in1c.css | |
---|---|---|---|
平均時間(s) | 5.52 | 5.30 | 5.20 |
從實驗1結果可以看出,合並資源和拆分資源對於資源的總加載時間沒有顯著影響。實驗中耗時最少的是拆分成3個資源的情況(5.2s),耗時最多的是合並成一個資源的情況(5.52s),但兩者也只不過相差6%。考慮到實驗環境具有一定隨機性,以及實驗重復次數只有10次,這個時間差並不能表征3種場景有明顯的時間差異性。
實驗 2
繼續增加css文件大小。
測試文件:xlarge1.css、xlarge2.css 、xlarge3.css,每個文件1.7M;xlarge-3in1.css,由前面3個css文件合並而成,大小為5.1M。parallel-xlarge.html引用xlarge1.css、xlarge2.css 、xlarge3.css, combined-xlarge.html引用xlarge-3in1.css。
測試過程同上,實驗結果如下:
xlarge-3in1.css | xlarge1.css、xlarge2.css、xlarge3.css | |
---|---|---|
平均時間(s) | 37.72 | 36.88 |
這組實驗的時間差只有2%,更小了,所以更無法說明合並資源和拆分資源的總加載時間有明顯差異性。
實際上,理想情況下,隨着資源體積變大,兩種資源加載方式所需時間將趨於相同。
從理論上解釋,因為HTTP的傳輸通道是基於TCP連接的,而TCP連接具有慢啟動的特性,剛開始時並沒有充分利用網絡帶寬,經過慢啟動過程后,逐漸占滿可利用的帶寬。
對於大資源而言,帶寬總是會被充分利用的,所以帶寬是瓶頸,即使使用更多的TCP連接,也不能帶來速度的提升。資源越大,慢啟動所占總的下載時間的比例就越小,絕大部分時間,帶寬都是被充分利用的,總數據量相同(拆分資源導致的額外Header在這種情況下完全可以忽略不計),帶寬相同,傳輸時間當然也相同。
實驗 3
減小css文件大小。
測試文件:medium1.css、medium2.css … medium6.css,每個文件9.4K;medium-6in1.css,由前面6個css文件合並而成,大小為56.4K。parallel-medium.html引用medium1.css、medium2.css … medium6.css, combined-medium.html 引用 medium-6in1.css。
實驗結果如下:
medium-6in1.css | medium1.css、medium2.css … medium6.css | |
---|---|---|
平均時間(ms) | 34.87 | 46.24 |
注意單位變成ms
實驗3的時間差是33%,雖然數值上只差12ms。先不多分析,繼續看實驗4。
實驗 4
繼續減小css文件大小,至幾十字節級別。
測試文件:small1.css、small2.css … small6.css,每個文件28B;small-6in1.css,由前面6個css文件合並而成,大小為173B。parallel-medium.html引用small1.css、small2.css … small6.css, combined-medium.html 引用 small-6in1.css。
實驗結果如下:
small-6in1.css | small1.css、small2.css … small6.css | |
---|---|---|
平均時間(ms) | 20.33 | 35 |
實驗4的時間差是72%。


提點
對於大資源,是否合並對於加載時間沒有明顯影響,但拆分資源可以更好的利用瀏覽器緩存,不會因為某個資源的更新導致所有資源緩存失效。
而資源合並后,任一資源的更新都會導致整體資源的緩存失效。另外還可以利用域名分片技術,將資源拆分部署到不同域名下,既可以分散服務器的壓力,又可以降低網絡抖動帶來的影響。
對於小資源,合並資源往往具有更快的加載速度,但在網絡帶寬狀況良好的情況下,因為提升的時間單位以ms計量,收益可以忽略。
如果網絡延遲很大,服務器響應速度又慢,則可以帶來一定收益,但在高延遲的網絡場景下,又要注意合並資源后可能帶來網絡往返次數的增加,進而影響到加載時間。
其實,看到這里,是合是分已經不重要了,重要的是我們要知道合分背后的原理是什么,和業務場景是怎樣的。