1. 程式人生 > >前端頁面效能優化的幾種方式

前端頁面效能優化的幾種方式

本文最初發表於部落格園,並在GitHub上持續更新前端的系列文章。歡迎在GitHub上關注我,一起入門和進階前端。

以下是正文。

前言

提升頁面效能優化的常見方式:

  • 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 響應頭中的ExpiresCache-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-ModifiedIf-Modified-Since

  • 第二對:ETagIf-None-Match

1、Last-ModifiedIf-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-ModifiedIf-Modified-Since一般來說都是非常可靠的,但有可能出現的問題是:伺服器上的資源變化了,但是最後的修改時間卻沒有變化。這一對header就無法解決這種情況。於是,下面這一對header出場了。

2、ETagIf-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)。

掃一掃,你將發現另一個全新的世界,而這將是一場美麗的意外: