前端性能優化--預加載技術


當我們談到前端的性能時,總是會提到比如合併、壓縮、緩存或者在服務器上開啓gzip之類的,目的都是爲了讓頁面加載的更快。

資源預拉取(prefetch)則是另一種性能優化的技術。通過預拉取可以告訴瀏覽器用戶在未來可能用到哪些資源。


Pre-fetching會提示瀏覽器那些未來一定或可能使用到的資源,有時在當前頁面見效,有些則在未來可能打開的頁面生效。 作爲開發者,我們比瀏覽器更懂自己的應用。我們可以利用這些技術提前告知瀏覽器web中用到的核心資源。

以前這種實踐也被稱爲『prebrowsing』。但這並不是一種單一的技術,實際上可以拆分成很多小點:dns-prefetch, subresource, prefetch, preconnect, 和 prerender.

DNS prefetch

DNS prefetching通過指定具體的URL來告知客戶端未來會用到相關的資源,這樣瀏覽器可以儘早的解析DNS。比如我們需要一個在example.com的圖片或者視頻文件。在<head>就可以這麼寫:

1

<linkrel="dns-prefetch"href="//example.com">

​當請求這個域名下的文件時就不需要等待DNS查詢了。項目中有用到第三方的代碼時這麼做尤其有益(其他的使用場景,比如當靜態資源和HTML不在一個域上,而在CDN上;又比如在重定向前可以加上DNS prefetch)。

Harry Roberts在他的前端性能優化文章中建議:

簡單的一行就能讓支持的瀏覽器提前解析DNS。也就是說在瀏覽器請求資源時,DNS查詢就已經準備好了。

這可能看起來是個非常微不足道的性能提升,而且還不是必須的–Chrome總是會做類似的處理,用戶只要在地址欄敲入一部分域名,如果命中了歷史常用的網站,Chrome就會提前解析DNS、預拉取頁面。(效果確實有限,但是聊勝於無)

caniuse

Preconnect

和DNS prefetch類似,preconnect不光會解析DNS,還會建立TCP握手連接和TLS協議(如果需要)。用法如下:

1

<linkrel="preconnect"href="http://css-tricks.com">

Ilya Grigorik寫了一篇文章詳細說明了這種技術:

現代瀏覽器竭盡所能的嘗試預測網站可能需要哪些鏈接。通過提前連接,瀏覽器可以提前建立必要的通信,消除了實際請求中DNS、TCP和TLS的耗時。不過,即使是隻能的現代瀏覽器,也沒辦法爲每個網站可靠的預測所有連接。

幸運的是開發者可以告訴瀏覽器哪些通信需要在實際請求發起前就提前建立連接。

舉個栗子: 上半張圖顯示了瀏覽器先拉html、再拉CSS並建立好CSSOM後,發現需要兩個外鏈的字體(在fonts.gstatic.com上),然後瀏覽器開始發起兩個請求,具體來說,需要對這個域進行DNS解析、TCP和TLS握手(一個建立後可以複用給另一個連接)。

1

2

<linkhref='https://fonts.gstatic.com'rel='preconnect'crossorigin>

<linkhref='https://fonts.googleapis.com/css?family=Roboto+Slab:700|Open+Sans'rel='stylesheet'>

下半張圖增加了上面的代碼來從fonts.gstatic.com preconnect資源。可以看到,瀏覽器在請求CSS的同時並行的建立字體資源需要的連接,等到真正開始需要字體時立刻就開始返回數據。

更多詳細的內容可以參考Ilya Grigorik的文章。

目前只支持Firefox 39+和Chrome 46+,具體參見caniuse

Prefetch

當能確定網頁在未來一定會使用到某個資源時,開發者可以讓瀏覽器提前請求並且緩存好以供後續使用。prefetch支持預拉取圖片、腳本或者任何可以被瀏覽器緩存的資源。

1

<linkrel="prefetch"href="image.png">

不同於DNS prefetch,上面的寫法可是會去請求、下載資源並且緩存起來。當然也是有一些發生條件的。比如,客戶端可能會在弱網絡下不去請求較大的字體文件,Firefox則只會在瀏覽器空閒的時候prefetch資源(譯者注:這裏是MDN上對瀏覽器空閒的定義和一些FAQ,建議閱讀)。

正如Bram Stein在他的文章中指出,prefetch很適用於優化webfonts的性能。以前,字體文件必須等DOM和CSSOM創建好後才能下載,可如果prefetch了字體,這個瓶頸就能輕鬆解決了。

注意:prefetch並沒有同域的限制

caniuse

Subresource

subresource可以用來指定資源是最高優先級的。比如,在Chrome和Opera中我們可以加上下面的代碼:

1

<linkrel="subresource"href="styles.css">

Chromium的文檔這麼解釋:

和 "Link rel=prefetch"的語義不同,"Link rel=subresource"是一種新的連接關係。rel=prefetch指定了下載後續頁面用到資源的低優先級,而rel=subresource則是指定當前頁面資源的提前加載。

所以,如果資源是在當前頁面需要,或者馬上就會用到,則推薦用subresource,否則還是用prefetch。

Prerender

prerender是一個重量級的選項,它可以讓瀏覽器提前加載指定頁面的所有資源。

1

<linkrel="prerender"  href="/thenextpage.html"/>

Steve Souders的文章詳細解釋了這個技術:

prerender就像是在後臺打開了一個隱藏的tab,會下載所有的資源、創建DOM、渲染頁面、執行JS等等。如果用戶進入指定的鏈接,隱藏的這個頁面就會進入馬上進入用戶的視線。Google Search多年前就利用了這個特性實現了Instant Pages功能。微軟最近也宣佈會讓Bing在IE11上用類似prerender的技術。

但是要注意,一定要在十分確定用戶回點某個鏈接時才用這個特性,否則客戶端就會無端的下載很多資源和渲染這個頁面。

正如任何提前的動作一樣,預判總是有一定風險出錯。如果提前的動作是昂貴的(比如高CPU、耗電、佔用帶寬),就要謹慎使用了。雖然不容易預判用戶會點進哪個頁面,但還是存在一些典型的場景:

  • 如果用戶搜索到了一個明顯正確的結果時,那麼這個頁面就很有可能被點入

  • 如果用戶在登錄頁面,那麼登錄成功後的頁面就很可能接下來會被加載了

  • 如果用戶在閱讀一個多頁面的文章或者有頁碼的內容時,下一頁就很可能會馬上被點擊了

利用Page Visibility API可以用來防止頁面在還沒真正展示給用戶時就觸發了JS的執行。

caniuse

未來:Preload

以上是已有的技術,我們再談談未來。 preload草案建議允許始終預加載某些資源,不像prefetch有可能被瀏覽器忽略,瀏覽器必須請求preload標記的資源。

1

<linkrel="preload"href="image.png">

然而,這項草案還沒有任何瀏覽器支持,不過值得關注。

 

總結

預判用戶的操作雖然不易,而且還需要大量的設計和測試工作,但是性能的提升是值得我們孜孜不倦的去追求的。如果我們願意試驗這些預加載技術,我們肯定能顯著地提升用戶體驗。

(譯者補一句,文章說的大部分預加載技術移動端都不支持,PC支持有限,但我們顯然應該知道這些技術的存在,並且持續的關注)

 

擴展閱讀


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章