preload、prefetch的認識

預加載

如今的網絡狀況雖然很樂觀,可是css

defer和async

當瀏覽器碰到 script 腳本的時候:html

<script src="script.js"></script>segmentfault

沒有 defer 或 async,瀏覽器會當即加載並執行指定的腳本,「當即」指的是在渲染該 script 標籤之下的文檔元素以前,也就是說不等待後續載入的文檔元素,讀到就加載並執行。瀏覽器

<script async src="script.js"></script>網絡

有 async,加載和渲染後續文檔元素的過程將和 script.js 的加載與執行並行進行(異步)。app

<script defer src="myscript.js"></script>異步

有 defer,加載後續文檔元素的過程將和 script.js 的加載並行進行(異步),可是 script.js 的執行要在全部元素解析完成以後,DOMContentLoaded 事件觸發以前完成。async

而後從實用角度來講呢,首先把全部腳本都丟到 </body> 以前是最佳實踐,由於對於舊瀏覽器來講這是惟一的優化選擇,此法可保證非腳本的其餘一切元素可以以最快的速度獲得加載和解析。性能

接着,咱們來看一張圖咯:fetch

clipboard.png

此圖告訴咱們如下幾個要點:

  1. defer 和 async 在網絡讀取(下載)這塊兒是同樣的,都是異步的(相較於 HTML 解析)
  2. 它倆的差異在於腳本下載完以後什麼時候執行,顯然 defer 是最接近咱們對於應用腳本加載和執行的要求的
  3. 關於 defer,此圖未盡之處在於它是按照加載順序執行腳本的,這一點要善加利用
  4. async 則是一個亂序執行的主,反正對它來講腳本的加載和執行是牢牢挨着的,因此無論你聲明的順序如何,只要它加載完了就會馬上執行
  5. 仔細想一想,async 對於應用腳本的用處不大,由於它徹底不考慮依賴(哪怕是最低級的順序執行),不過它對於那些能夠不依賴任何腳本或不被任何腳本依賴的腳原本說倒是很是合適的,

preload和refetch

preload一般在頁面中,咱們須要加載一些腳本和樣式,而使用 preload 能夠對當前頁面所需的腳本、樣式等資源進行預加載,而無需等到解析到 script 和 link 標籤時才進行加載。這一機制使得資源能夠更早的獲得加載並可用,且更不易阻塞頁面的初步渲染,進而提高性能。

使用方式
將 link 標籤的 rel 屬性的值設爲 preload,as 屬性的值爲資源類型(如腳本爲 script,樣式表爲 style)

<head>
  <meta charset="utf-8">
  <title>preload example</title>
  <!-- 對 style.css 和 index.js 進行預加載 -->
  <link rel="preload" href="style.css" as="style">
  <link rel="preload" href="index.js" as="script">

  <link rel="stylesheet" href="style.css">
</head>

<body>
  <div id="app"></div>

  <script src="index.js"></script>
</body>

prefetchpreload 同樣,都是對資源進行預加載,可是 prefetch 加載的資源通常不是用於當前頁面的,即將來極可能用到的這樣一些資源,簡單點說就是其餘頁面會用到的資源。固然,prefetch 不會像 preload 同樣,在頁面渲染的時候加載資源,而是利用瀏覽器空閒時間來下載。當進入下一頁面,就可直接從 disk cache 裏面取,既不影響當前頁面的渲染,又提升了其餘頁面加載渲染的速度。

使用方式
preload 很類似,無需指定 as 屬性:

<head>
  <meta charset="utf-8">
  <title>preload example</title>
  <!-- 對 style.css 和 index.js 進行 preload 預加載 -->
  <link rel="preload" href="style.css" as="style">
  <link rel="preload" href="index.js" as="script">

  <!-- 對資源進行 prefetch 預加載 -->
  <link rel="prefetch" href="next.css">
  <link rel="prefetch" href="next.js">

  <link rel="stylesheet" href="style.css">
</head>

<body>
  <div id="app"></div>

  <script src="index.js"></script>
</body>

總結:對當前頁面須要的資源,使用 preload 進行預加載,對其它頁面須要的資源進行 prefetch 預加載。

Subresource和Prerender

subresource能夠用來指定資源是最高優先級的。好比,在Chrome和Opera中咱們能夠加上下面的代碼:

<link rel="subresource" href="styles.css">

Chromium的文檔這麼解釋:
和 "Link rel=prefetch"的語義不一樣,"Link rel=subresource"是一種新的鏈接關係。rel=prefetch指定了下載後續頁面用到資源的低優先級,而rel=subresource則是指定當前頁面資源的提早加載。

因此,若是資源是在當前頁面須要,或者立刻就會用到,則推薦用subresource,不然仍是用prefetch。

prerender是一個重量級的選項,它可讓瀏覽器提早加載指定頁面的全部資源。

<link rel="prerender" href="/thenextpage.html" />

Steve Souders的文章詳細解釋了這個技術:
prerender就像是在後臺打開了一個隱藏的tab,會下載全部的資源、建立DOM、渲染頁面、執行JS等等。若是用戶進入指定的連接,隱藏的這個頁面就會進入立刻進入用戶的視線。Google Search多年前就利用了這個特性實現了Instant Pages功能。微軟最近也宣佈會讓Bing在IE11上用相似prerender的技術。

可是要注意,必定要在十分肯定用戶回點某個連接時才用這個特性,不然客戶端就會無故的下載不少資源和渲染這個頁面。
正如任何提早的動做同樣,預判老是有必定風險出錯。若是提早的動做是昂貴的(好比高CPU、耗電、佔用帶寬),就要謹慎使用了。雖然不容易預判用戶會點進哪一個頁面,但仍是存在一些典型的場景:

若是用戶搜索到了一個明顯正確的結果時,那麼這個頁面就頗有可能被點入
若是用戶在登陸頁面,那麼登陸成功後的頁面就極可能接下來會被加載了
若是用戶在閱讀一個多頁面的文章或者有頁碼的內容時,下一頁就極可能會立刻被點擊了
利用Page Visibility API能夠用來防止頁面在還沒真正展現給用戶時就觸發了JS的執行。

參考:
defer和async
prefetch與 preload
prefetch預加載
preload立即加載
加載技術概述
dnc fetch

Prerender Subresource

相關文章
相關標籤/搜索