Web 性能優(yōu)化:控制關(guān)鍵請求的優(yōu)先級
翻譯自:https://calibreapp.com/blog/critical-request,作者 Ben Schwarz,已獲得作者授權(quán),原文略作中文語境調(diào)整。
性能優(yōu)化有很多角度,其中一個關(guān)鍵是控制關(guān)鍵請求的優(yōu)先級,從而達到性能優(yōu)化的效果。本文以一種相對系統(tǒng)的方式來進行該方法的探討。
構(gòu)建一個網(wǎng)站服務(wù)看似簡單:發(fā)送 HTML,瀏覽器識別出接下來需要加載什么資源。然后,我們耐心的等待頁面就緒。
你不知道的是,這背后發(fā)生了很多事情。你有沒有想過,瀏覽器是如何判斷哪些資產(chǎn)需要以什么順序被請求的?
內(nèi)容概覽:
什么是資產(chǎn)優(yōu)先級? Chrome 如何安排資源優(yōu)先級? 什么樣的請求是關(guān)鍵的? Lighthouse 審計:避免關(guān)鍵請求的依賴鏈。 技術(shù):控制請求優(yōu)先級。 技術(shù):圖片懶加載。 技術(shù):font-display 關(guān)鍵請求檢查清單。
什么是資產(chǎn)優(yōu)先級?
現(xiàn)代瀏覽器用流式解析器來解析 HTML —— 在完全下載之前,就可以在 HTML 標(biāo)記之中找到資產(chǎn)。當(dāng)瀏覽器找到資產(chǎn)時,就會按照預(yù)先確定的優(yōu)先級把它們加到網(wǎng)絡(luò)隊列中。
可視化的分析一個網(wǎng)站以及它的資源優(yōu)先級。
預(yù)先確定的優(yōu)先級可能是:Lowest, Low, Medium, High 和 Highest 其中之一。通過優(yōu)先級分配,瀏覽器可以知道哪個請求對頁面快速加載最關(guān)鍵。
本文以 Chrome 為主,但其他瀏覽器對請求的優(yōu)先級排序也是類似的。你可以在 Chrome、Safari、Firefox 或 Edge 開發(fā)者工具中,通過右鍵單擊任何表格標(biāo)題并選擇“優(yōu)先級”來查看請求優(yōu)先級。

請求優(yōu)先級也可以在Chrome的 Performance 面板中看到:

Chrome 如何安排資源優(yōu)先級?
資源按出現(xiàn)的順序被添加到網(wǎng)絡(luò)隊列中。然后瀏覽器會把網(wǎng)絡(luò)活動投入用于盡快獲取到最高優(yōu)先級的資源。
每種資源類型都有自己的一組規(guī)則來決定分配給它的優(yōu)先級:
| 資源類型 | 優(yōu)先級 |
|---|---|
| HTML | Highest |
| Fonts | High |
| Stylesheets | Highest |
| 通過 @import 加載的 Stylesheets | Highest,會被安排在阻塞腳本之后。 |
| Images | 默認(rèn)是 Low,在初始視口中渲染時升級為 Medium。 |
| JavaScripts | Low, Medium 或 High。查看 Addy Osmani 的 JavaScript Loading Priorities in Chrome[1] 來獲取更多細(xì)節(jié)。 |
| Ajax,XHR,或者 fetch() API | High |
什么樣的請求是關(guān)鍵的?
關(guān)鍵請求是指顯示在頁面初始視口里的資源。
這些資源對 Core Web Vitals[2] 中諸如 Largest Contentful Paint(最大內(nèi)容繪制)[3] 和 First Contentful Paint[4](首次內(nèi)容繪制)這些指標(biāo)有著直接的影響。以這篇文章為例,我們可以直觀地識別出視口需要的資產(chǎn),以便完全渲染。

對于這個頁面來說,關(guān)鍵的請求是:
HTML CSS LOGO 3 個字權(quán)重 頭條圖片(Largest Contentful Paint 元素)
這些資源(注意,沒有 JavaScript)對于初始視口的視覺展示至關(guān)重要。他們應(yīng)該先被加載。
在審計你的頁面時,我們推薦:
對頁面進行可視化審計,注意視口中的關(guān)鍵元素。 最初的 5 個 HTTP 請求應(yīng)該是:HTML + 4 個關(guān)鍵請求。 確保關(guān)鍵的請求不要被重定向。 更新你的站點,確保關(guān)鍵資源是優(yōu)化過、壓縮過、有緩存能力且有正確的 HTTP 頭的。
Lighthouse 審計:避免關(guān)鍵請求的依賴鏈
谷歌的 Lighthouse 套件附帶了一個名為“避免關(guān)鍵請求的依賴鏈”的審計,高亮展示了被鏈接在一起的請求。當(dāng)瀏覽器在發(fā)出請求是由于另一個請求引用它時(也稱為依賴項),我們稱之為請求鏈。

關(guān)鍵請求鏈最常見的一個例子是,比如某些樣式表內(nèi)部加載了在初始頁面視口顯示的字體或背景圖像。
@font-face?{
??font-family:?'Calibre';
??font-weight:?400;
??font-display:?swap;
??src:?url('/Calibre-Regular.woff2')?format('woff2'),?url('/Calibre-Regular.woff')
??????format('woff');
}
.carousel-bg?{
??background-image:?url('/images/main-masthead-bg.png');
}
你可以使用 Lighthouse 的“避免關(guān)鍵請求的依賴鏈”的審計來診斷和識別出頁面中的資源依賴。
減少關(guān)鍵請求鏈的整體數(shù)量,有助于更快的 Largest Contentful Paint(最大內(nèi)容繪制) 和即時的用戶體驗。
為了減少關(guān)鍵請求鏈的影響,請使用以下 Web 性能策略:
減少請求的數(shù)量 使用壓縮和最小化來減少資源的大小 將非關(guān)鍵腳本標(biāo)記為異步 考慮將 @font-face聲明直接內(nèi)聯(lián)到 HTML 中避免使用 CSS 背景圖片或 @import使用預(yù)加載提前獲取關(guān)鍵資源 使用 bundlephobia[5] 尋找該庫的更小替代品
技術(shù):控制請求優(yōu)先級
請求優(yōu)先級會被 preload[6] 的使用所影響。預(yù)加載的資源會被分配為高優(yōu)先級,并且在頁面的初始加載中優(yōu)先被請求。
<link?rel="preload"?href="Calibre-Regular.woff2"?as="font"?crossorigin?/>

使用 preload,相當(dāng)于告訴瀏覽器:“你可能還不知道它是什么,但我們需要它?!?/strong>
預(yù)加載有助于優(yōu)化關(guān)鍵請求,但也不要濫用!如果預(yù)加載了過多的資源,頁面性能會劣化[7]。
預(yù)加載會影響 Largest Contentful Paint(最大內(nèi)容繪制) 和 Cumulative Layout Shift[8](累積布局偏移)。在某些情況下,影響可能是負(fù)面的。我們建議使用預(yù)加載請求進行試驗,但一定要前后仔細(xì)測試。
技術(shù):圖片懶加載
默認(rèn)情況下,瀏覽器會加載 HTML中指定的所有圖片,哪怕用戶實際上永遠不會看見的那些。懶加載允許你指定某些圖片只有當(dāng)用戶滾動頁面到它們附近時才去請求。如果用戶不滾動頁面,瀏覽器就不會加載這些圖片。
使用這種方法,您可以提高整體渲染速度,并節(jié)省不必要的數(shù)據(jù)傳輸。懶加載是提高 Largest Contentful Paint(最大內(nèi)容繪制)的有效方法。
過去,我們使用第三方庫或手寫腳本實現(xiàn)懶加載。如今,它已內(nèi)置在瀏覽器中[9]。
使用方法如下:
在已經(jīng)知道會出現(xiàn)在視口下方的 元素上加上loading="lazy"屬性。當(dāng)頁面滾動時,懶加載的圖片已經(jīng)加載完成,準(zhǔn)備好展示了。

累積布局偏移(CLS)標(biāo)識用戶交互期間的頁面布局偏移。請確保設(shè)置圖像的 width 和 height 屬性,以避免懶加載的圖像在渲染時,頁面重新布局。
就是這樣!懶加載的實現(xiàn)方法并不復(fù)雜,但是對加速渲染非常有幫助。一定要盡可能用上。
技術(shù):font-display
根據(jù) HTTP Archive 中的統(tǒng)計,69% 的站點使用 web 字體[10]。不幸的是,不幸的是,在大多數(shù)情況下,它們提供的體驗都低于標(biāo)準(zhǔn)。
每個人都目睹過字體出現(xiàn),然后消失,改變了粗細(xì),頁面仿佛被震動了一樣。這些移位現(xiàn)在會被累積布局移位(CLS)指標(biāo)所測量。
我們已經(jīng)證實了用 控制字體請求的優(yōu)先級對渲染速度有驚人的影響。所以顯而易見,我們在大部分情況下都應(yīng)該提高字體請求的優(yōu)先級。
我們可以用 CSS font-display[11] 進一步提高渲染速度。這個 CSS 屬性允許你控制字體在請求和加載后如何展示。
你可以用
font-display來優(yōu)化 Largest Contentful Paint[12](最大內(nèi)容繪制)和 Cumulative Layout Shift[13](累積布局偏移)
有五個 font-display 選項[14]供您選擇。我們推薦使用 swap 選項,它可以先立即呈現(xiàn)文本,然后在加載網(wǎng)絡(luò)字體后立即替換。
給定這樣的字體棧:
body?{
??font-family:?Calibre,?Helvetica,?Arial;
}
瀏覽器會先用 Helvetica 字體展示(或者 Arial,如果你的系統(tǒng)里沒有安裝 Helvetica)直到 Calibre 字體加載完成。
沒有 font-display
文字在 HTML、CSS 和網(wǎng)絡(luò)字體加載完后才展示:

沒有 font-display,文本在 2.44 秒顯示。
加上 font-display: swap
文字在 HTML 下載并且處理后立刻顯示了,取得 1.6 秒的進步:

使用 font-display,文本在 835 毫秒顯示。
font-display 在主流現(xiàn)代瀏覽器里支持的不錯[15],你可以從今天開始使用它了。
關(guān)鍵請求檢查清單
有了這些知識,您現(xiàn)在應(yīng)該能夠為您的站點選擇最關(guān)鍵的資產(chǎn),并相應(yīng)地對它們進行優(yōu)先級排序。如果你想進一步推進優(yōu)先級和速度的優(yōu)化,請遵循以下清單:
啟用Chrome開發(fā)者工具的 Priority 列。 盡可能減少所需的關(guān)鍵請求的數(shù)量。 檢查哪些請求必須在用戶看到完整渲染的頁面之前發(fā)出。使用 對這些關(guān)鍵請求進行優(yōu)先處理。使用 link prefetching[16],優(yōu)化可能在下一個導(dǎo)航中使用的資源。 使用 Link Preload HTTP headers[17] 聲明要在 HTML 完全交付之前預(yù)加載的資源。 確保圖像尺寸正確的提前寫好。 使用內(nèi)聯(lián) SVG 展示 Logo 和圖標(biāo)。 使用更好的圖像格式,如 AVIF 或 WEBP。 使用 font-display: swap在初始渲染中展示文本。使用壓縮的字體格式,如 WOFF2 或 variable fonts(可變形字體)。 在 Chrome://net-internals/#events 中查看 Chrome 的網(wǎng)絡(luò)事件。 記住:最快的請求,是從未發(fā)出的請求。
祝你優(yōu)化快樂!
參考資料
JavaScript Loading Priorities in Chrome: https://tech.bytedance.net/articles/7025506101156118536#:~:text=JavaScript%20Loading%20Priorities%20in%20Chrome
[2]Core Web Vitals: https://tech.bytedance.net/articles/7025506101156118536#:~:text=%E8%BF%99%E4%BA%9B%E8%B5%84%E6%BA%90%E5%AF%B9-,Core%20Web%20Vitals,-%E4%B8%AD%E8%AF%B8%E5%A6%82%20Largest
[3]Largest Contentful Paint(最大內(nèi)容繪制): https://web.dev/lcp/
[4]First Contentful Paint: https://tech.bytedance.net/articles/7025506101156118536#:~:text=First%20Contentful%20Paint
[5]使用 bundlephobia: https://bundlephobia.com/package/[email protected]
[6]preload: https://tech.bytedance.net/articles/7025506101156118536#:~:text=%E4%BC%98%E5%85%88%E7%BA%A7%E4%BC%9A%E8%A2%AB-,preload,-%E7%9A%84%E4%BD%BF%E7%94%A8%E6%89%80
[7]頁面性能會劣化: https://tech.bytedance.net/articles/7025506101156118536#:~:text=%E8%BF%87%E5%A4%9A%E7%9A%84%E8%B5%84%E6%BA%90%EF%BC%8C-,%E9%A1%B5%E9%9D%A2%E6%80%A7%E8%83%BD%E4%BC%9A%E5%8A%A3%E5%8C%96,-%E3%80%82
[8]Cumulative Layout Shift: https://web.dev/cls/
[9]內(nèi)置在瀏覽器中: https://caniuse.com/?search=lazy
[10]69% 的站點使用 web 字體: https://httparchive.org/reports/state-of-the-web?start=latest#fonts
[11]CSS font-display: https://css-tricks.com/almanac/properties/f/font-display/
[12]Largest Contentful Paint: https://web.dev/lcp
[13]Cumulative Layout Shift: https://web.dev/cls/
[14]五個 font-display 選項: https://css-tricks.com/almanac/properties/f/font-display/
[15]支持的不錯: https://caniuse.com/mdn-api_fontface_display
[16]link prefetching: https://developer.mozilla.org/en-US/docs/Web/HTTP/Link_prefetching_FAQ
[17]Link Preload HTTP headers: https://www.w3.org/TR/preload/
最后
如果你覺得這篇內(nèi)容對你挺有啟發(fā),我想邀請你幫我三個小忙:
點個「在看」,讓更多的人也能看到這篇內(nèi)容(喜歡不點在看,都是耍流氓 -_-)
歡迎加我微信「qianyu443033099」拉你進技術(shù)群,長期交流學(xué)習(xí)...
關(guān)注公眾號「前端下午茶」,持續(xù)為你推送精選好文,也可以加我為好友,隨時聊騷。

