原文釋出於我的 GitHub blog,歡迎關注
原文: Resource Hints – What is Preload, Prefetch, and Preconnect?
作者:BRIAN JACKSON
今天我們將研究一下能顯著提升頁面效能的方法 —— 資源提示與指令。你也許聽說過 preload,prefetch 和 preconnect,可是我們想研究的更深一點,搞清他們之間的區別並且充分的利用它們。它們帶來的好處包括允許前端開發人員來優化資源的載入,減少往返路徑並且在瀏覽頁面時可以更快的載入到資源。
Preload
Preload 是一個新的控制特定資源如何被載入的新的 Web 標準,這是已經在 2016 年 1 月廢棄的 subresource prefetch 的升級版。這個指令可以在 <link>
中使用,比如 <link rel="preload">
。一般來說,最好使用 preload 來載入你最重要的資源,比如影象,CSS,JavaScript 和字型檔案。這不要與瀏覽器預載入混淆,瀏覽器預載入只預先載入在HTML中宣告的資源。preload 指令事實上克服了這個限制並且允許預載入在 CSS 和JavaScript 中定義的資源,並允許決定何時應用每個資源。
Preload 與 prefetch 不同的地方就是它專注於當前的頁面,並以高優先順序載入資源,Prefetch 專注於下一個頁面將要載入的資源並以低優先順序載入。同時也要注意 preload 並不會阻塞 window 的 onload
事件。
使用 Preload 的好處
使用 preload 指令的好處包括:
- 允許瀏覽器來設定資源載入的優先順序因此可以允許前端開發者來優化指定資源的載入。
- 賦予瀏覽器決定資源型別的能力,因此它能分辨這個資源在以後是否可以重複利用。
- 瀏覽器可以通過指定
as
屬性來決定這個請求是否符合 content security policy。 - 瀏覽器可以基於資源的型別(比如 image/webp)來傳送適當的
accept
頭。
舉例
這裡有一個非常基本的預載入影象的例子:
<link rel="preload" href="image.png">
複製程式碼
這裡有一個預載入字型的例子,記住:如果你的預載入需要 CORS 的跨域請求,那麼也要加上 crossorigin 的屬性。
<link rel="preload" href="https://example.com/fonts/font.woff" as="font" crossorigin>
複製程式碼
這裡有一個通過 HTML 和 JavaScript 預載入樣式表的例子:
<!-- Via markup -->
<link rel="preload" href="/css/mystyles.css" as="style">
複製程式碼
<!-- Via JavaScript -->
<script>
var res = document.createElement("link");
res.rel = "preload";
res.as = "style";
res.href = "css/mystyles.css";
document.head.appendChild(res);
</script>
複製程式碼
來自 filament group 的 Scott Jehl 也有了一些相關研究並寫了 async loaded styles using markup 說明了 preload 是不阻塞頁面渲染的!
瀏覽器對 Preload 的支援
Chrome 50 在 2016 年 4 月新增了對 Preload 的支援,Opera 37 等瀏覽器也支援它。不過目前 Mozilla Firefox 還沒有確定要支援,Microsoft Edge 開發者版似乎要支援。
(譯者注,下圖是 2018 年 7 月末瀏覽器對 preload 的支援情況)
可以讀一下我們對 preload 的一篇深入分析的文章。
Prefetch
Prefetch 是一個低優先順序的資源提示,允許瀏覽器在後臺(空閒時)獲取將來可能用得到的資源,並且將他們儲存在瀏覽器的快取中。一旦一個頁面載入完畢就會開始下載其他的資源,然後當使用者點選了一個帶有 prefetched 的連線,它將可以立刻從快取中載入內容。有三種不同的 prefetch 的型別,link,DNS 和 prerendering,下面來詳細分析。
Link Prefetching
像上面提到的,link prefetching 假設使用者將請求它們,所以允許瀏覽器獲取資源並將他們儲存在快取中。瀏覽器會尋找 HTML <link>
元素中的 prefetch 或者 HTTP 頭中如下的 Link:
- HTML:
<link rel="prefetch" href="/uploads/images/pic.png">
- HTTP Header:
Link: </uploads/images/pic.png>; rel=prefetch
"這項技術有為很多有互動網站提速的潛力,但並不會應用在所有地方。對於某些站點來說,太難猜測使用者下一步的動向,對於另一些站點,提前獲取資源可能導致資料過期失效。還有很重要的一點,不要過早進行 prefetch,否則會降低你當前瀏覽的頁面的載入速度 —— Google Developers"
除了 Safari, iOS Safari 和 Opera Mini,現代瀏覽器已經支援了 link Prefetch,Chrome 和 Firefox 還會在網路皮膚上顯示這些 prefetched 資源。
(譯者注,下圖是 2018 年 7 月末瀏覽器對 link prefetch 的支援情況)
DNS Prefetching
DNS prefetching 允許瀏覽器在使用者瀏覽頁面時在後臺執行 DNS 的解析。如此一來,DNS 的解析在使用者點選一個連結時已經完成,所以可以減少延遲。可以在一個 link 標籤的屬性中新增 rel="dns-prefetch'
來對指定的 URL 進行 DNS prefetching,我們建議對 Google fonts,Google Analytics 和 CDN 進行處理。
"DNS 請求在頻寬方面流量非常小,可是延遲會很高,尤其是在移動裝置上。通過 prefetching 指定的 DNS 可以在特定的場景顯著的減小延遲,比如使用者點選連結的時候。有些時候,甚至可以減小一秒鐘的延遲 —— Mozilla Developer Network"
這也對需要重定向的資源很有用,如下:
<!-- Prefetch DNS for external assets -->
<link rel="dns-prefetch" href="//fonts.googleapis.com">
<link rel="dns-prefetch" href="//www.google-analytics.com">
<link rel="dns-prefetch" href="//opensource.keycdn.com">
<link rel="dns-prefetch" href="//cdn.domain.com">
複製程式碼
不過要注意的是 Chrome 已經在敲擊位址列的時候做了類似的事情,比如 DNS preresolve 和 TCP preconnect,這些措施太酷了!你可以通過 chrome://dns/
來檢視你的優化列表。
你可以利用 Pagespeed 的過濾器 insert_dns_prefetch 來自動化的為所有域名插入 <link rel="dns-prefetch">
。
DNS prefetch 已經被除了 Opera Mini 之外的所有現代瀏覽器支援了。
(譯者注,下圖是 2018 年 7 月末瀏覽器對 DNS-prefetch 的支援情況)
Prerendering
Prerendering 和 prefetching 非常相似,它們都優化了可能導航到的下一頁上的資源的載入,區別是 prerendering 在後臺渲染了整個頁面,整個頁面所有的資源。如下:
<link rel="prerender" href="https://www.keycdn.com">
複製程式碼
"prerender
提示可以用來指示將要導航到的下一個 HTML:使用者代理將作為一個 HTML 的響應來獲取和處理資源,要使用適當的 content-types 獲取其他內容型別,或者不需要 HTML 預處理,可以使用 prefetch
。—— W3C"
Source: Chrome Prerendering
要小心的使用 prerender,因為它將會載入很多資源並且可能造成頻寬的浪費,尤其是在移動裝置上。還要注意的是,你無法在 Chrome DevTools 中進行測試,而是在 chrome://net-internals/#prerender
中看是否有頁面被 prerendered 了,你也可以在 prerender-test.appspot.com 進行測試。
除了 Mozilla Firefox,Safari,iOS Safari,Opera Mini 和 Android 瀏覽器外的一些現代瀏覽器已經支援了 prerendering。
除了多餘的資源載入外,使用 prefetch 還有一切 額外的副作用,比如對隱私的損害:
- Web 統計將會收到影響而變大,儘管 Google 說已經限制了這個標籤。看看這個關於頁面分析將會被影響而在一次點選時產生兩個 session 的 文章。
- 由於可能從未訪問的站點下載了更多的頁面(尤其是隱匿下載正在變得更加先進和多樣化),使用者的安全將面臨更多的風險。
- 如果預取訪問未經授權的內容,使用者可能違反其網路或組織的可接受使用策略。
可以讀一下我們對 prefetching 的一篇深入分析的文章。
Preconnect
本文介紹的最後一個資源提示是 preconnect,preconnect 允許瀏覽器在一個 HTTP 請求正式發給伺服器前預先執行一些操作,這包括 DNS 解析,TLS 協商,TCP 握手,這消除了往返延遲併為使用者節省了時間。
"Preconnect 是優化的重要手段,它可以減少很多請求中的往返路徑 —— 在某些情況下可以減少數百或者數千毫秒的延遲。—— lya Grigorik"
preconnect 可以直接新增到 HTML 中 link 標籤的屬性中,也可以寫在 HTTP 頭中或者通過 JavaScript 生成,如下是一個為 CDN 使用 preconnect 的例子:
<link href="https://cdn.domain.com" rel="preconnect" crossorigin>
複製程式碼
如下是為 Google Fonts 使用 preconnect 的例子,通過給 fonts.gstatic.com
加入 preconnect 提示,瀏覽器將立刻發起請求,和 CSS 請求並行執行。在這個場景下,preconnect 從關鍵路徑中消除了三個 RTTs(Round-Trip Time) 並減少了超過半秒的延遲,lya Grigorik 的 eliminating RTTS with preconnect 一文中有更詳細的分析。
使用 preconnect 是個有效而且剋制的資源優化方法,它不僅可以優化頁面並且可以防止資源利用的浪費。除了 Internet Explorer,Safari,IOS Safari 和 Opera Mini 的現代瀏覽器已經支援了 preconnect。
可以讀一下我們對 preconnect 的一篇深入分析的文章。
總結
希望你現在對 preload,prefetch 和 preconnect 有了一些理解並知道如何利用它們來加速資源的載入,希望在未來的幾個月能看到更多的瀏覽器支援這些預載入提示並且有更多的開發者使用它們。
你對這些資源提示有何理解?你試著使用過它們嗎?歡迎留言討論。