前端效能優化 - Resource Hints 資源預載入

korbinzhao發表於2018-01-08

Resource Hints 是非常好的一種效能優化方法,可以大大降低頁面載入時間,給使用者更加流暢的使用者體驗。

現代瀏覽器使用大量預測優化技術來預測使用者行為和意圖,這些技術有預連線、資源與獲取、資源預渲染等。

Resource Hints 的思路有如下兩個:

  • 當前將要獲取資源的列表
  • 通過當前頁面或應用的狀態、使用者歷史行為或 session 預測使用者行為及必需的資源

實現Resource Hints的方法有很多種,可分為基於 link 標籤的 DNS-prefetch、subresource、preload、 prefetch、preconnect、prerender,和本地儲存 localStorage。

DNS-Prefect

DNS 預讀取是一項使瀏覽器主動去執行域名解析的功能,其範圍包括文件的所有連線,無論是圖片的,CSS 的,還是 JavaScript 等其他使用者能夠點選的 URL。這樣能夠減少使用者點選連結時的延遲。

DNS 請求需要的頻寬非常小,但是延遲卻有點高,這點在手機網路上特別明顯。預讀取DNS能讓延遲明顯減少一些,例如使用者點選連結時。在某些情況下,延遲能減少一秒鐘。

在某些瀏覽器中這個預讀取的行為將會與頁面實際內容並行發生(而不是序列)。正因如此,某些高延遲的域名的解析過程才不會卡住資源的載入。

這樣可以極大的加速(尤其是行動網路環境下)頁面的載入。在某些圖片較多的頁面中,在發起圖片載入請求之前預先把域名解析好將會有至少5%的圖片載入速度提升。

開啟和關閉DNS預讀取

可以通過在伺服器端傳送 X-DNS-Prefectch-Control 報頭,或是在文件中使用值為 http-equiv 的 標籤:

<meta http-equiv="x-dns-prefetch-control" content="off">
複製程式碼

可以通過將 content 的引數設定為 on 來改變設定

強制查詢特定主機名

可以通過使用 rel 屬性值為 link type 中的 dns-prefetch 的 標籤來對特定域名進行預讀取:

<link rel="dns-prefetch" href="http://www.spreadfirefox.com/">
複製程式碼

強制對域名進行預讀取在有的情況下很有用,比如,在網站的主頁上,強制在整個網站上頻繁引用的域名的預解析,及時他們不再主頁本身上使用。及時主頁的效能可能不受影響,這將提高整體站點的效能。

Preconnect

現代瀏覽器都試著預測網站將來需要哪些連線,然後預先建立 socket 連線,從而消除昂貴的 DNS 查詢、TCP握手和 TLS 往返開銷。然而,瀏覽器並不夠聰明,並不能準確預測每個網站的所有預連線目標。prefetch 允許我們告訴瀏覽器我們需要哪些預連線, preconnect 不僅完成 DNS 解析,同事還會進行 TCP 握手和建立傳輸層協議。

<link rel="preconnect" href="//example.com">
<link rel="preconnect" href="//cdn.example.com" crossorigin>
複製程式碼

Prefetch

如果確定某個資源將來一定會被使用,我們可以讓瀏覽器預先請求該資源並放入瀏覽器快取中。使用方法:

<link rel="prefetch" href="image.png">
複製程式碼

與DNS預讀取不同,prefetch 預獲取真正請求並下載了資源,並儲存在快取中。單預獲取還依賴於一些條件,某些預獲取可能會被瀏覽器忽略,例如一個非常緩慢的網路中獲取一個龐大的字型檔案。

注意:

  • chrome 和 firefox 的網路皮膚中都有資源預獲取的記錄
  • 預獲取沒有資源同源策略限制

Subresources

除 prefetch 之外的另一種預獲取方式,這種方式的預獲取資源具有最高的優先順序,在所有 prefetch 項之前進行:

<link rel="subresource" href="styles.css">
複製程式碼

所以,如果資源是當前頁面必須的,或者資源需要儘快可用,那麼最好使用 subresource 而不是 prefetch。

Prerender

prerender 會預先載入文件的所有資源:

<link rel="prerender" href="http://example.com">
複製程式碼

這類似於在一個隱藏的 tab 頁中開啟了某一個連結,下載所有資源建立 DOM 結構、完成頁面佈局、應用 CSS 樣式和執行 JS 指令碼等。當使用者真正訪問該連結時,隱藏的頁面就切換為可見,使頁面看起來就是shunjian 載入完成一樣。

需要注意的是不要濫用該特性,當你知道使用者一定會點選某個連結時,才可以進行預渲染,否則瀏覽器將無條件地下載所有預渲染需要的資源。

Preload

preload 預載入是區於 prefetch 的另一種 resouce hint 的方式。用於任意型別的資源。用法如下:

 <link rel="preload" href="style.css" as="style">
  <link rel="preload" href="main.js" as="script">
複製程式碼

preload 和 prefetch 的區別在於,preload 是告訴瀏覽器預先請求當前頁面需要的資源,具有高優先順序,prefetch 是告訴瀏覽器使用者將來可能在其他頁面(非本頁面)可能使用到的資源,瀏覽器會在空閒的情況下,預先載入這些資源到 http 快取裡。

LocalStorage 快取機制

前面介紹的基於 link 標籤的方法存在瀏覽器相容問題。目前來看,比較通用的一種資源預載入方案是利用 LocalStorage 來進行部分資源和資料的快取。目前在各大主流網際網路廠商中都有使用。

使用 LocalStorage 來做資源快取,需要解決快取更新機制。

但也存在一個短板,就是存在 XSS 安全隱患。因為 localStorage 的資訊是可以在客戶端被任意修改的。

因此,LocalStorage 快取很有用,但是也有明顯缺陷。

參考資料

相關文章