前端效能最佳化——採用高效的快取策略提供靜態資源
一、發現效能問題
透過 Chrome 開發者工具的 Lighthouse 工具對目標站點的某個頁面進行分析,其生成的報告如圖所示:
由分析報告可知,該目標站點存在多項待最佳化的效能問題,如減少未使用的 JavaScript 和採用高效的快取策略提供靜態資源等問題,本文主要分析並解決採用高效的快取策略提供靜態資源問題。
二、分析效能問題
Lighthouse 會標記所有未被快取的靜態資源:
Lighthouse 認為一個資源是可快取的,當且僅當以下所有條件都滿足:
- 該資源是字型、影像、媒體檔案、指令碼或樣式表。
- 該資源具有 200、203 或 206 HTTP 狀態碼。
- 該資源沒有顯式的 no-cache 策略。
當頁面未透過審計時,Lighthouse 會將結果列在一個具有三列的表格中:
列名 | 說明 |
---|---|
網址 | 可快取資源的位置 |
快取 TTL | 資源當前的快取持續時間 |
傳輸檔案大小 | 如果被標記的資源已經被快取,使用者可以節省多少資料的估算值 |
透過分析 Lighthouse 工具對目標站點生成的檢測報告,發現採用高效的快取策略提供靜態資源這一項中的快取 TTL 列,有一些靜態資原始檔的值為 None,也就是說該目標站點有部分靜態資源未被快取,那麼這部分資源在重複訪問時,會重複向伺服器傳送請求,因此該情況將明顯影響目標站點效能。
三、解決效能問題
為了使靜態資源快取,需要在伺服器端配置 HTTP 響應標頭。標頭控制瀏覽器快取的行為。以下是一些有關快取的重要標頭:
- Cache-Control:用於控制資源的快取機制。透過設定值為 public 或 private 來指定資源是否可以被快取,並透過設定 max-age 指定資源應該被快取的時間長度。
- Expires:允許指定一個過期時間,過期後,瀏覽器必須重新獲取資源。
- ETag:允許伺服器標識資源,並使用 If-None-Match 請求頭進行快取驗證。
- Last-Modified:允許伺服器指定資源最後修改的時間,並使用 If-Modified-Since 請求頭進行快取驗證。
請配置你的伺服器返回 Cache-Control HTTP 響應頭:
Cache-Control: max-age=31536000
max-age 引數告訴瀏覽器它應該將資源快取多長時間,單位為秒。以下示例將持續時間設定為 31536000,對應於 1 年:60 秒 × 60 分鐘 × 24 小時 × 365 天= 31536000 秒。
以在 Nginx 中配置 Cache-Control 響應頭為例:
http {
server {
location / {
root /html;
index index.html index.htm;
# # 設定快取時間為 1 天
# expires 1d;
# 開啟快取,並設定一年的快取期
add_header Cache-Control "public,max-age=31536000";
}
}
}
可以透過配置 expires 引數和 Cache-Control 的 max-age 來指定快取期。
add_header Cache-Control "public,max-age=31536000";
開啟了快取,並指定了快取型別為 public,表示響應可以被客戶端和代理伺服器快取,max-age 指定了資源的快取期為 31536000 秒。
Nginx 伺服器端設定 Cache-Control
響應頭後,訪問靜態資源的響應如圖所示:
需要注意的是,長時間的快取期存在一個問題:使用者可能看不到靜態檔案的更新。但是可以透過配置構建工具來解決該問題,在靜態資原始檔名中嵌入雜湊來避免這個問題,以便每個版本都是唯一的,從而促使瀏覽器從伺服器獲取新版本。(要了解如何使用 webpack 嵌入雜湊,請參閱 webpack 的快取指南。)
如果資源經常更新且實時性很重要,那麼可以將其快取設定為 no-cache,但瀏覽器仍會快取該資源,不過首先會與伺服器進行檢查,以確保資源仍然是最新的。
此外,並不是快取期越長越好。而是需要根據實際需求進行權衡,以決定資源的最佳快取期。
透過在 Nginx 開啟快取,並設定合適的快取期,目標站點的效能檢測報告如圖所示:
由上圖可知,效能評分並沒有改變,但在診斷結果下已沒有採用高效的快取策略提供靜態資源這一項,這一項已經被移入已透過的稽核,也就是該項透過在伺服器設定 Cache-Control 的方式得到了效能上的最佳化。