前端頁面效能優化的幾種方式
以下是正文。
前言
提升頁面效能優化的常見方式:
1、資源壓縮合並,減少http請求
2、非核心程式碼非同步載入 --> 非同步載入的方式 --> 非同步載入的區別
3、利用瀏覽器快取 --> 快取的分類 --> 快取的原理
快取是所有效能優化的方式中最重要的一步【重要】
有的人可能會回答local storage 和session storage,其實不是這個。瀏覽器快取和儲存不是一回事。
- 4、使用CDN
瀏覽器第一次開啟頁面時,快取是起不了作用的。這個時候,CDN就上場了。
- 5、DNS預解析
一、資源壓縮合並,減少http請求
合併圖片(css sprites)、CSS和JS檔案合併、CSS和JS檔案壓縮
圖片較多的頁面也可以使用 lazyLoad 等技術進行優化。
精靈圖等
二、非核心程式碼非同步載入
非同步載入的方式:(這裡不說框架,只說原理)
動態指令碼載入
defer
async
動態指令碼載入
使用document.createElement建立一個script標籤,即document.createElement('script')
,然後把這個標籤載入到body上面去。
參考連結:
defer
通過非同步的方式載入defer1.js檔案:
<script src="./defer1.js" defer></script>
async
HTmL5新增特性。
通過非同步的方式載入async1.js檔案:
<script src="./async1.js" async></script>
defer和async的區別
defer:在HTML解析完之後才會執行。如果是多個,則按照載入的順序依次執行。
async:在載入完之後立即執行。如果是多個,執行順序和載入順序無關。
程式碼舉例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <!--通過非同步的方式引入兩個外部的js檔案--> <script src="./defer1.js" defer></script> <script src="./defer2.js" defer></script> </head> <body> <script> console.log('同步任務'); </script> </body> </html>
上方列印的結果是:
同步任務
defer1
defer2
因為defer的載入是有順序的,所以兩個引入defer檔案按順序執行。如果把引入的檔案改為async的方式載入,列印的結果可能是:
同步任務
async2
async1
參考連結:
三、利用瀏覽器快取
快取:資原始檔(比如圖片)在本地存有副本,瀏覽器下次請求的時候,可能直接從本地磁盤裡讀取,而不會重新請求圖片的url。
快取分為:
強快取
協商快取
強快取
強快取:不用請求伺服器,直接使用本地的快取。
強快取是利用 http 響應頭中的Expires
或Cache-Control
實現的。【重要】
瀏覽器第一次請求一個資源時,伺服器在返回該資源的同時,會把上面這兩個屬性放在response header中。比如:
注意:這兩個response header屬性可以只啟用一個,也可以同時啟用。當response header中,Expires和Cache-Control同時存在時,Cache-Control的優先順序高於Expires。
下面講一下二者的區別。
1、Expires
:伺服器返回的絕對時間。
是較老的強快取管理 response header。瀏覽器再次請求這個資源時,先從快取中尋找,找到這個資源後,拿出它的Expires跟當前的請求時間比較,如果請求時間在Expires的時間之前,就能命中快取,否則就不行。
如果快取沒有命中,瀏覽器直接從伺服器請求資源時,Expires Header在重新請求的時候會被更新。
缺點:
由於Expires
是伺服器返回的一個絕對時間,存在的問題是:伺服器的事件和客戶端的事件可能不一致。在伺服器時間與客戶端時間相差較大時,快取管理容易出現問題,比如隨意修改客戶端時間,就能影響快取命中的結果。所以,在http1.1中,提出了一個新的response header,就是Cache-Control。
2、Cache-Control
:伺服器返回的相對時間。
http1.1中新增的 response header。瀏覽器第一次請求資源之後,在接下來的相對時間之內,都可以利用本地快取。超出這個時間之後,則不能命中快取。重新請求時,Cache-Control
會被更新。
協商快取
協商快取:瀏覽器發現本地有資源的副本,但是不太確定要不要使用,於是去問問伺服器。
當瀏覽器對某個資源的請求沒有命中強快取(也就是說超出時間了),就會發一個請求到伺服器,驗證協商快取是否命中。
協商快取是利用的是兩對Header:
第一對:
Last-Modified
、If-Modified-Since
第二對:
ETag
、If-None-Match
1、Last-Modified
、If-Modified-Since
。過程如下:
(1)瀏覽器第一次請求一個資源,伺服器在返回這個資源的同時,會加上Last-Modified
這個 response header,這個header表示這該資源在伺服器上的最後修改時間:
(2)瀏覽器再次請求這個資源時,會加上If-Modified-Since
這個 request header,這個header的值就是上一次返回的Last-Modified
的值:
(3)伺服器收到第二次請求時,會比對瀏覽器傳過來的If-Modified-Since
和資源在伺服器上的最後修改時間Last-Modified
,判斷資源是否有變化。如果沒有變化則返回304 Not Modified,但不返回資源內容(此時,伺服器不會返回 Last-Modified 這個 response header);如果有變化,就正常返回資源內容(繼續重複整個流程)。這是伺服器返回304時的response header:
(4)瀏覽器如果收到304的響應,就會從快取中載入資源。
缺點:
Last-Modified
、If-Modified-Since
一般來說都是非常可靠的,但有可能出現的問題是:伺服器上的資源變化了,但是最後的修改時間卻沒有變化。這一對header就無法解決這種情況。於是,下面這一對header出場了。
2、ETag
、If-None-Match
。過程如下:
(1)瀏覽器第一次請求一個資源,伺服器在返回這個資源的同時,會加上ETag
這個 response header,這個header是伺服器根據當前請求的資源生成的唯一標識。這個唯一標識是一個字串,只要資源有變化這個串就不同,跟最後修改時間無關,所以也就很好地補充了Last-Modified
的不足。如下:
(2)瀏覽器再次請求這個資源時,會加上If-None-Match
這個 request header,這個header的值就是上一次返回的ETag
的值:
3)伺服器第二次請求時,會對比瀏覽器傳過來的If-None-Match
和伺服器重新生成的一個新的ETag
,判斷資源是否有變化。如果沒有變化則返回304 Not Modified,但不返回資源內容(此時,由於ETag重新生成過,response header中還會把這個ETag返回,即使這個ETag並無變化)。如果有變化,就正常返回資源內容(繼續重複整個流程)。這是伺服器返回304時的response header:
(4)瀏覽器如果收到304的響應,就會從快取中載入資源。
提示:如果面試官問你:與瀏覽器快取相關的http header有哪些?你能寫出來嗎?這是一個亮點。
參考連結:
四、使用CDN
怎麼最快地讓使用者請求資源。一方面是讓資源在傳輸的過程中變小,另外就是CDN。
要注意,瀏覽器第一次開啟頁面的時候,瀏覽器快取是起不了作任何用的,使用CDN,效果就很明顯。
五、DNS預解析(dns-prefetch)
通過 DNS 預解析來告訴瀏覽器未來我們可能從某個特定的 URL 獲取資源,當瀏覽器真正使用到該域中的某個資源時就可以儘快地完成 DNS 解析。
第一步:開啟或關閉DNS預解析
你可以通過在伺服器端傳送 X-DNS-Prefetch-Control 報頭。或是在文件中使用值為 http-equiv 的meta標籤:
<meta http-equiv="x-dns-prefetch-control" content="on">
需要說明的是,在一些高階瀏覽器中,頁面中所有的超連結(<a>
標籤),預設打開了DNS預解析。但是,如果頁面中採用的https協議,很多瀏覽器是預設關閉了超連結的DNS預解析。如果加了上面這行程式碼,則表明強制開啟瀏覽器的預解析。(如果你能在面試中把這句話說出來,則一定是你出彩的地方)
第二步:對指定的域名進行DNS預解析
如果我們將來可能從 smyhvae.com 獲取圖片或音訊資源,那麼可以在文件頂部的 標籤中加入以下內容:
<link rel="dns-prefetch" href="http://www.smyhvae.com/">
當我們從該 URL 請求一個資源時,就不再需要等待 DNS 解析的過程。該技術對使用第三方資源特別有用。
參考連結:
我的公眾號
想學習程式碼之外的軟技能?不妨關注我的微信公眾號:生命團隊(id:vitateam
)。
掃一掃,你將發現另一個全新的世界,而這將是一場美麗的意外: