有一種優化方法叫做preload
在程式開發中,優化是必不可少的,今天學習的優化方法叫做preload。
奇技淫巧 --- Preload
- 在網頁載入時,為了提高網頁載入的效能,我們一般會選擇延遲載入一部分資源和執行。
- 另一種情況是想要儘早的載入資源,但是等到合適的時機在執行。影響因素包括了依賴條件,執行條件,執行順序等等。 通常我們會這樣做:
- 通過插入一個頁面元素來宣告一個資源(如img、link、script),這種方式會將資源的載入和執行耦合
- 通過AJAX來載入資源。這種方式只有在時機成熟時才會載入資源,解決了執行時機問題。但是瀏覽器無法預解析,也就無法提前載入。另外如果頁面有大量的阻塞指令碼,就會造成延遲。
那麼有沒有辦法既提前載入資源,又能解耦載入和執行呢?這時候就有人提出了Preload解決方案
什麼是Preload
preload是一個預載入關鍵字它顯式地向瀏覽器宣告一個需要提前載入的資源。使用方式如下:
- 在head標籤中插入這行程式碼,也可以用js生成再插入head標籤中。
<link rel="preload" href="resource-url" as="xxx">
複製程式碼
- 在HTTP請求頭中加上
Link:<resource-url>;rel=preload;as=xx
,當瀏覽器“看”到這樣的宣告後,就會以一定的優先順序在後臺載入資源,載入完的資源放在 HTTP快取中。而等到要真正執行時,再按照正常方式用標籤或者程式碼載入,即可從 HTTP 快取取出資源。
Preload的特點
- 提前載入資源
- 資源的載入和執行分離
- 不會延遲網頁的load事件(除非 Preload 資源剛好是阻塞 window 載入的資源)
Preload 跟其他提前載入資源以及載入和執行分離的方案有什麼區別?
- 預測解析方案
在瀏覽器解析HTML資源時,可以同時收集外鏈資源,並且新增到一個列表,在後臺並行下載。預測解析也實現了提前載入以及載入和執行分離。
和preload的區別:
- 僅限於解析 HTML 時收集的外鏈資源。如果是程式裡非同步載入的資源則是無法提前收集到的。
- 瀏覽器不暴露類似於 Preload 中的 onload 事件,也就無法更細粒度的控制資源的執行。
- async
async指令碼是一載入完就立即執行,會阻塞window的onload事件,而且目前async僅限於指令碼資源的載入。
而Preload可以實現和async一樣的非同步載入,並且不侷限於指令碼。比如以下程式碼會將CSS程式碼載入完就立即執行,作用到網頁中。
<link rel="preload" href="./style.css" as="style" onload="this.rel='stylesheet'">
// 注:如果頁面存在同步阻塞指令碼,等指令碼執行完後,樣式才會作用到網頁。
// 這樣是因為 Preload 的資源不會阻塞 window 的 onload 事件。
複製程式碼
- defer
defer實現了資源的載入和執行分離,並且能保證defer的資源按照HTML裡的出現順序執行。但是它和async一樣,目前只能作用於指令碼資源。
Preload 則適用多種資源型別。Preload 的資源也能像 defer 的資源一樣延遲執行並保證執行順序。
- server push
HTTP/2的 Server Push 也實現了資源的提前載入以及載入執行的分離。不過 Server Push 節省了一個網路來回,我們可以結合 Server Push 優化 Preload,比如伺服器識別到文件裡的Preload的資源就主動推送Preload的資源。如果不希望伺服器推送,則增加 nopush 屬性: Link: <./style.css>; rel=preload; as=style; nopush
另外 Server Push 只能推送同域資源。而 Preload 則可以支援跨域資源。
什麼時候使用Preload
任何需要,想要先預載入再執行的資源,想要提高頁面渲染效能的場景都可以使用Preload。
例如:
- 在單頁面應用中,提前載入路由檔案,提高切換路由時的渲染速度。現在大型的單頁面應用通常都會使用非同步載入路由檔案。當使用者切換路由時再非同步載入相應的模組可能會存在效能問題。這時就可以用 Preload 提前載入,提升效能。
- 提前載入字型檔案。眾所周知,字型檔案需要等到CSSOM構建完成,並且作用到頁面元素之後,才會開始載入,這樣就會導致頁面的字型閃動(FOUT),所以這時就可以使用Preload提前載入字型,消除FOUT。
Preload相容性問題
在 PC 上實現了 Preload 的瀏覽器包括: Chrome 50+,Saferi 11.1+ 。Edge 17+支援 HTML 方式,不支援 HTTP header 方式。移動端:iOS Safari 11.4+,Android Chrome 67
不支援 Preload的瀏覽器會自動忽略它,並採用普通的載入方式。因此可以將此功能作為一種漸進增強方式用到我們的網頁應用中。