雖然我們生活在一個(gè)寬帶無(wú)處不在、4/5G 幾乎全覆蓋的時(shí)代,但網(wǎng)站加載緩慢還是常態(tài),就算我們打開(kāi)一個(gè)以文本為中心的新聞網(wǎng)站,都可能需要至少 30 秒才能開(kāi)始閱讀。畢竟在內(nèi)容膨脹時(shí)代,一張照片就能輕易超過(guò) 1MB 大小,許多網(wǎng)站為了顯示幾段文本,還會(huì)單獨(dú)加載至少 10MB 的 JS 和自定義字體。
對(duì)此,對(duì)優(yōu)化和極簡(jiǎn)主義充滿熱情的資深 Web 開(kāi)發(fā) Nathaniel 告訴我們,你應(yīng)該讓你的網(wǎng)頁(yè)盡力控制在 14KB 以內(nèi),而且即使對(duì)于以富媒體為中心的網(wǎng)站,這條 14KB 的規(guī)則可能仍然值得遵循。如果 14KB 不足以用于最終布局,則需要優(yōu)先考慮 “首屏” 字節(jié),可以用發(fā)送給訪問(wèn)者的前 14KB 數(shù)據(jù)來(lái)渲染一些有用的東西,減少用戶還沒(méi)有開(kāi)始閱讀就流失掉的機(jī)會(huì)。
網(wǎng)頁(yè)越小,加載速度就越快——這一點(diǎn)都不奇怪。
但令人感到驚訝的是,14KB 網(wǎng)頁(yè)的加載速度比 15KB 要快得多——可能快 612 毫秒——而 15KB 和 16KB 網(wǎng)頁(yè)之間的加載速度差異微乎其微。
這是 TCP 慢啟動(dòng)算法導(dǎo)致的。本文將介紹這個(gè)算法、它的原理以及為什么你應(yīng)該關(guān)注它。但首先我們需要快速過(guò)一遍一些基礎(chǔ)知識(shí)。
1 TCP 是什么
傳輸控制協(xié)議(Transmission Control Protocol,TCP)是一種使用 IP 協(xié)議可靠地發(fā)送數(shù)據(jù)包的方法——有時(shí)被稱為 TCP/IP。
當(dāng)瀏覽器向你的網(wǎng)站(或圖像或樣式表)發(fā)出請(qǐng)求時(shí),它會(huì)使用 HTTP 請(qǐng)求。HTTP 建立在 TCP 之上,一個(gè) HTTP 請(qǐng)求通常由許多 TCP 數(shù)據(jù)包組成。IP 只是一個(gè)將數(shù)據(jù)包從互聯(lián)網(wǎng)上的一個(gè)位置發(fā)送到另一個(gè)位置的系統(tǒng)。IP 沒(méi)有檢查數(shù)據(jù)包是否成功到達(dá)目的地的方法。
對(duì)于網(wǎng)站來(lái)說(shuō),確保所有的數(shù)據(jù)到達(dá)請(qǐng)求端是非常關(guān)鍵的,否則我們可能會(huì)因?yàn)閬G失數(shù)據(jù)包無(wú)法獲得完整的網(wǎng)頁(yè)。但在網(wǎng)絡(luò)的其他應(yīng)用場(chǎng)景中,這一點(diǎn)并不那么重要——比如流媒體直播視頻。
TCP 是 IP 的擴(kuò)展,瀏覽器和網(wǎng)站服務(wù)器通過(guò)它告訴對(duì)方哪些數(shù)據(jù)包已經(jīng)成功到達(dá)。
服務(wù)器發(fā)送一些數(shù)據(jù)包,然后等待瀏覽器已經(jīng)收到數(shù)據(jù)包的響應(yīng)(這叫確認(rèn)或 ACK),然后它繼續(xù)發(fā)送更多的數(shù)據(jù)包——或者如果它沒(méi)有收到 ACK,將再次發(fā)送相同的數(shù)據(jù)包。
2 什么是 TCP 慢啟動(dòng)
TCP 慢啟動(dòng)是一種算法,服務(wù)器用它來(lái)確定一次可以發(fā)送多少數(shù)據(jù)包。
當(dāng)瀏覽器第一次連接到服務(wù)器時(shí),服務(wù)器無(wú)法知道它們之間的帶寬是多少。帶寬是指在單位時(shí)間內(nèi)網(wǎng)絡(luò)可以傳輸?shù)臄?shù)據(jù)量。通常以比特 / 秒(b/s)為單位。我們可以用管道來(lái)作類比——把帶寬想象成每秒從管道流出多少水。
服務(wù)器不知道網(wǎng)絡(luò)連接可以處理多少數(shù)據(jù)——所以它先發(fā)送少量且安全的數(shù)據(jù)——通常是 10 個(gè) TCP 數(shù)據(jù)包。如果這些數(shù)據(jù)包成功地到達(dá)網(wǎng)站訪問(wèn)者,他們的計(jì)算機(jī)返回確認(rèn)(ACK),表示數(shù)據(jù)包已經(jīng)被收到了。然后,服務(wù)器發(fā)送更多的數(shù)據(jù)包,但這一次它將數(shù)據(jù)包的數(shù)量增加了一倍。
這個(gè)過(guò)程會(huì)不斷重復(fù),直到數(shù)據(jù)包丟失,服務(wù)器沒(méi)有收到 ACK。(此時(shí),服務(wù)器會(huì)繼續(xù)發(fā)送數(shù)據(jù)包,但速度較慢)。
這就是 TCP 慢啟動(dòng)的要點(diǎn)——在現(xiàn)實(shí)當(dāng)中,雖然算法各不相同,但這是它的基本原理。
3 那么 14KB 這個(gè)數(shù)字是怎么來(lái)的
大多數(shù) Web 服務(wù)器的 TCP 慢啟動(dòng)算法都是從發(fā)送 10 個(gè) TCP 數(shù)據(jù)包開(kāi)始的。
TCP 數(shù)據(jù)包最大長(zhǎng)度為 1500 字節(jié)。這個(gè)最大值不是由 TCP 規(guī)范設(shè)置的,它來(lái)自于以太網(wǎng)標(biāo)準(zhǔn)。
每個(gè) TCP 數(shù)據(jù)包的標(biāo)頭占了 40 個(gè)字節(jié),其中 16 個(gè)字節(jié)用于 IP,另外 24 個(gè)字節(jié)用于 TCP。
這樣每個(gè) TCP 數(shù)據(jù)包還剩下 1460 個(gè)字節(jié)。10 x 1460 = 14600 字節(jié),或大約 14KB!
因此,如果你能把網(wǎng)站的網(wǎng)頁(yè)——或網(wǎng)頁(yè)的關(guān)鍵部分——壓縮到 14KB,就可以為訪問(wèn)者節(jié)省大量的時(shí)間——他們和網(wǎng)站服務(wù)器之間的往返時(shí)間。
一個(gè)數(shù)據(jù)往返能有多糟糕?但人們非常沒(méi)有耐心——一個(gè)數(shù)據(jù)往返可能會(huì)出奇地長(zhǎng),具體多長(zhǎng)取決于延遲…… 延遲是指數(shù)據(jù)包從源傳輸?shù)侥康牡厮ㄙM(fèi)的時(shí)間。如果帶寬是每秒鐘可以通過(guò)管道的水的數(shù)量,那么延遲就是一滴水進(jìn)入管道后從另一端流出所花費(fèi)的時(shí)間。
下面是一個(gè)關(guān)于延遲有多糟糕的例子。
衛(wèi)星網(wǎng)絡(luò)
衛(wèi)星網(wǎng)絡(luò)是由環(huán)繞地球軌道的衛(wèi)星提供的,在人煙稀少的地區(qū)、石油鉆井平臺(tái)、游輪以及飛機(jī)上,人們可以使用這種網(wǎng)絡(luò)。
為了說(shuō)明這種糟糕的延遲,我們想象一群在石油鉆井平臺(tái)工作的兄弟把骰子忘在了家里,他們需要通過(guò) missingdice.com(少于 14KB)來(lái)玩《龍與地下城》游戲。
首先,他們中的一個(gè)用手機(jī)發(fā)出一個(gè)網(wǎng)頁(yè)請(qǐng)求……
手機(jī)將請(qǐng)求發(fā)送到鉆井平臺(tái)的 WiFi 路由器,路由器將數(shù)據(jù)發(fā)送給平臺(tái)上的衛(wèi)星天線,我們假設(shè)這可能需要 1 毫秒時(shí)間。
然后,衛(wèi)星天線將數(shù)據(jù)發(fā)送到地球軌道上方的衛(wèi)星。
通常,這是通過(guò)在地球表面上方 35786 公里處運(yùn)行的軌道衛(wèi)星實(shí)現(xiàn)的。光速為 299792458 米 / 秒,所以信息從地球發(fā)送到衛(wèi)星需要 120 毫秒。然后,衛(wèi)星將信息傳回地面接收站,這又需要 120 毫秒。
然后,地面站必須將請(qǐng)求發(fā)送到位于地球任意位置的服務(wù)器(當(dāng)光通過(guò)光纖電纜傳輸時(shí),速度會(huì)降至每秒 200000000 米)。如果地面站和服務(wù)器之間的距離等于紐約到倫敦之間的距離,那么大約需要 28 毫秒,如果地面站和服務(wù)器之間的距離等于紐約到悉尼之間的距離,則需要 80 毫秒——所以我們姑且定一個(gè) 60 毫秒的數(shù)字(這個(gè)數(shù)字便于計(jì)算)。
然后,服務(wù)器需要處理請(qǐng)求,這可能需要 10 毫秒,然后服務(wù)器再次將它發(fā)送出去。
回到地面站,進(jìn)入太空,回到衛(wèi)星天線,然后回到無(wú)線路由器,再到手機(jī)上。
手機(jī) -> WiFi 路由器 -> 衛(wèi)星天線 -> 衛(wèi)星 -> 地面站 -> 服務(wù)器 -> 地面站 -> 衛(wèi)星 -> 衛(wèi)星天線 -> WiFi 路由器 -> 手機(jī)
如果我們算一下,就是 10 + (1 + 120 + 120 + 60) x 2 = 612 毫秒。
這是每次往返額外的 612 毫秒——也許這看起來(lái)不是很長(zhǎng)時(shí)間,但你的網(wǎng)站可能只是為了獲取第一個(gè)資源就需要許多個(gè)往返。
另外,HTTPS 在完成第一個(gè)往返之前需要額外的兩次往返——這使延遲達(dá)到了 1836 毫秒!
對(duì)于生活在陸地上的人,延遲又是怎樣的
衛(wèi)星網(wǎng)絡(luò)似乎是一個(gè)極端的例子——我選擇它作為例子是因?yàn)樗軌虺浞终f(shuō)明了網(wǎng)絡(luò)延遲這個(gè)問(wèn)題——但對(duì)于生活在陸地上的人來(lái)說(shuō),延遲可能比這更糟糕,原因有很多。
2G 網(wǎng)絡(luò)的延遲通常在 300 毫秒到 1000 毫秒之間;
3G 網(wǎng)絡(luò)的延遲可以在 100 毫秒到 500 毫秒之間;
嘈雜的移動(dòng)網(wǎng)絡(luò)——比如在一個(gè)異常擁擠的地方,比如音樂(lè)節(jié);
處理大流量的服務(wù)器;
其他一些不好的東西。
不穩(wěn)定的網(wǎng)絡(luò)連接也會(huì)導(dǎo)致數(shù)據(jù)包丟失——導(dǎo)致需要另一個(gè)往返來(lái)獲取丟失的數(shù)據(jù)包。
4 了解了 14KB 法則,接下來(lái)可以做些什么
當(dāng)然,你應(yīng)該讓你的網(wǎng)頁(yè)盡可能的小——你愛(ài)你的訪客,你希望他們開(kāi)心。將每個(gè)頁(yè)面的大小控制在 14KB 以內(nèi)是一個(gè)不錯(cuò)的主意。
這 14KB 可以是壓縮數(shù)據(jù)——所以實(shí)際上可以對(duì)應(yīng)大約 50KB 的未壓縮數(shù)據(jù)——這已經(jīng)非常慷慨了。要知道,阿波羅 11 的制導(dǎo)計(jì)算機(jī)只有 72KB 內(nèi)存。
去掉自動(dòng)播放的視頻、彈出窗口、Cookie、Cookie 橫幅、社交網(wǎng)絡(luò)按鈕、跟蹤腳本、JavaScript 和 CSS 框架,以及所有其他人們不喜歡的垃圾——你可能就能實(shí)現(xiàn) 14KB 法則。
假設(shè)你已經(jīng)盡力將所有內(nèi)容控制在 14KB 以內(nèi),但仍然做不到——但 14KB 法則仍然很有用。
你可以用發(fā)送給訪問(wèn)者的前 14KB 數(shù)據(jù)來(lái)渲染一些有用的東西——例如一些關(guān)鍵的 CSS、JS 和解釋如何使用你的應(yīng)用程序的前幾段文本。 需要注意的是,14KB 法則包含了 HTTP 標(biāo)頭——這些是未壓縮的(即使是 HTTP/2 的第一個(gè)響應(yīng)),也包含圖片,所以你應(yīng)該只加載在頁(yè)面上方的內(nèi)容,并保持它們最小,或者使用占位符,讓訪問(wèn)者知道他們?cè)诘却恍└玫膬?nèi)容。
關(guān)于這個(gè)法則的一些注意事項(xiàng)
14KB 法則更像是一種經(jīng)驗(yàn)之談,而不是計(jì)算的基本法則。
一些服務(wù)器已經(jīng)將 TCP 慢啟動(dòng)初始窗口從 10 個(gè)數(shù)據(jù)包增加到 30 個(gè);
有時(shí)服務(wù)器知道它可以從更大數(shù)量的數(shù)據(jù)包開(kāi)始傳輸,因?yàn)樗褂?TLS 握手來(lái)建立一個(gè)更大的窗口;
服務(wù)器可以緩存路由可管理的數(shù)據(jù)包數(shù)量,并在下一次連接時(shí)發(fā)送更多的數(shù)據(jù)包;
還有其他需要注意的地方——這里有一篇文章更深入地探討關(guān)于為什么 14KB 法則并不總是這么回事。
HTTP/2 和 14KB 法則
有一種觀點(diǎn)認(rèn)為,在使用 HTTP/2 時(shí),14KB 法則不再適用。我已經(jīng)讀了所有我能讀到的關(guān)于這個(gè)問(wèn)題的東西,但我還沒(méi)有看到任何證據(jù)表明使用 HTTP/2 的服務(wù)器已經(jīng)停止使用 TCP 慢啟動(dòng)(從 10 個(gè)數(shù)據(jù)包開(kāi)始)。
HTTP/3 和 QUIC
與 HTTP/2 類似,有一種觀點(diǎn)認(rèn)為 HTTP/3 和 QUIC 將廢除 14KB 法則——事實(shí)并非如此。實(shí)際上,QUIC 仍然建議使用 14KB 法則。