開發者可以控制瀏覽器資源的加載順序,但這種控制的粒度能做到多細呢?
本文來聊聊資源加載優先級的問題。
瀏覽器解析資源的優先級
當瀏覽器開始解析網頁,並開始下載圖片、Script
以及 CSS
等資源的時候,瀏覽器會為每個資源分配一個代表資源下載優先級的 fetch priority
標志。
而資源下載的順序就取決於這個優先級標志,這個優先級標志的計算邏輯會受很多因素的影響:
Script
、CSS
、Font
、Image
等不同的資源類型會有不同的優先級。- 在
HTML文檔
中引用資源的位置或順序也會影響資源的優先級(例如在viewport
中的圖片資源可能具有高優先級,而在<link>
標簽中加載的,阻塞渲染的CSS
則擁有更高的優先級)。 - 有
preload
屬性的資源有助於瀏覽器更快地發現資源、其實也是影響資源加載的優先級。 Script
的async
或defer
屬性都會影響它的優先級。
綜合考慮這些因素,下面是現在大多數的資源在 Chrome
中的優先級和排序方式:
瀏覽器按照資源被發現的順序下載具有相同計算優先級的資源。你可以在 DevTools Network
下看到分配給不同資源的優先級:
盡管瀏覽器很擅長這件事情,但是並不是所有情況下默認的下載優先級都是最佳的。
為什么你需要 Priority Hints ?
知道了瀏覽器為資源分配下載優先級的方式,我們就可以根據實際的業務場景去適當做一些調整:
- 根據期望的資源的下載順序放置資源標簽,例如
<script>
和<link>
,具有相同優先級的資源通常按照它們被放置的順序加載。 - 使用
preload
屬性提前下載必要的資源,特別是對於瀏覽器早期不易發現的資源。 - 使用
async
或defer
下載非首屏不需要阻塞的資源。 - 延遲加載一些首屏內容,以便瀏覽器可以將可用的網絡帶寬用於更重要的首屏資源。
這些技術可以讓我們更好的控制瀏覽器的優先級計算,從而提高網頁的 Core Web Vitals
性能指標。例如,我們將網頁關鍵的背景圖像進行預加載,可以改進最大內容繪制指標 ( LCP
)。
但是,以上的幾個技術也不能足以讓我們在所有場景都能把優先級控制的很好,比如下面的幾個場景:
- 網站現在有多個首屏圖像,但它們並具有相同的優先級,比如在輪播圖中只有第一張圖需要更高的優先級。
- 將
<script>
聲明為async
或defer
可以告訴瀏覽器異步加載它們。但是,根據我們上面的分析,這些<script>
也被分配了 “低” 優先級。但是你可能希望在確保瀏覽器異步下載它們的同時提高它們的優先級,尤其是一些對用戶體驗至關重要腳本。 - 瀏覽器為
JavaScript fetch API
異步獲取資源或數據分配了高優先級,但是某些場景下你可能不希望以高優先級請求所有資源。 - 瀏覽器為
CSS
、Font
分配了同樣的高優先級,但是並不是所有CSS
和Font
資源都是一樣重要的,你可能需要更具體的指定它們的優先級。
所以,瀏覽器又給我們提供了一個能更好控制資源優先級加載的功能:Priority Hints
。
importance 屬性
你可以使用一個 importance
屬性來更細力度的控制資源加載的優先級,包括 link、img、script
和 iframe
這些標簽。
importance
屬性可以指定三個值:
high
:你認為該資源具有高優先級,並希望瀏覽器對其進行優先級排序。low
:你認為該資源的優先級較低,並希望瀏覽器降低其優先級。auto
:采用瀏覽器的默認優先級。
<!-- We don't want a high priority for this above-the-fold image -->
<img src="/images/in_viewport_but_not_important.svg" importance="low" alt="I'm an unimportant image!">
<!-- We want to initiate an early fetch for a resource, but also deprioritize it -->
<link rel="preload" href="/js/script.js" as="script" importance="low">
<script>
fetch('https://example.com/', {importance: 'low'}).then(data => {
// Trigger a low priority fetch
});
</script>
<!-- The third-party contents of this iframe can load with a low priority -->
<iframe src="https://example.com" width="600" height="400" importance="low"></iframe>
實際應用
提升 LCP 圖像的優先級
現在,你擁有了更靈活的優先級配置,你可以用它去提升你網頁的 Core Web Vitals
。
比如,在 Google Flights
這個網頁中,影響它 LCP
指標的主要原因是它的背景圖片,現在我們用 importance
屬性提升它加載的優先級:
<img src="lcp-image.jpg" importance="high">
可以發現,網頁的 LCP
從 2.6s
提高到 1.9s
:
降低首屏圖片的優先級
使用 importance
屬性降低可能不重要的首屏圖片的優先級,比如輪播圖中后面的圖片:
<ul class="carousel">
<img src="img/carousel-1.jpg" importance="high">
<img src="img/carousel-2.jpg" importance="low">
<img src="img/carousel-3.jpg" importance="low">
<img src="img/carousel-4.jpg" importance="low">
</ul>
降低預加載資源的優先級
想要阻止預加載資源和其他關鍵資源的競爭,可以降低其優先級:
<!-- Lower priority only for non-critical preloaded scripts -->
<link rel="preload" as="script" href="critical-script.js">
<link rel="preload" href="/js/script.js" as="script" importance="low">
<!-- Preload CSS and hero images without blocking other resources -->
<link rel="preload" as="style" href="theme.css" importance="low" onload="this.rel=stylesheet">
腳本的優先級
如果頁面上有一些必要的交互腳本,但不需要阻塞其他資源,你可以把它們標記為具有高優先級,同時異步加載它們:
<script src="async_but_important.js" async importance="high"></script>
如果腳本依賴於特定的 DOM
節點,則它們不能被標記為異步加載。但是如果它們不是首屏渲染必備的,你可以降低它們的優先級:
<script src="blocking_but_unimportant.js" importance="low"></script>
fetch
瀏覽器默認會以高優先級執行 fetch 請求,你可以降低不太關鍵的數據請求的優先級:
// Important validation data (high by default)
let authenticate = await fetch('/user');
// Less important content data (suggested low)
let suggestedContent = await fetch('/content/suggested', {importance: 'low'});
開始試用
你可以在 Chrome
的設置中打開 Experimental Web Platform Features
就可以試用這一特性啦。
參考
https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Releases/1.5/Changing_the_priority_of_HTTP_requests
https://developer.chrome.com/blog/new-in-chrome-96/#pri-hints
https://web.dev/priority-hints/
轉自https://mp.weixin.qq.com/s/kaT3qAku86_ihSJA8oC0yQ