1. 程式人生 > >前端頁面效能優化

前端頁面效能優化

前言

最近參加了兩次社招,發現社招面試都會問到效能優化以及框架原理。當中效能優化即使我知道好幾種,然而我面試時總是很容易想不起來,只答出了兩三種。因此,寫一篇部落格來對效能優化做一下研究,加深理解。

1、壓縮 合併

對於 前端效能優化 自然要關注 首屏 開啟速度,而這個速度,很大因素是花費在網路請求上,那麼怎麼減少網路請求的時間呢?

  • 減少網路請求次數
  • 減小檔案體積
  • 使用 CDN 加速

所以 壓縮、合併 就是一個解決方案,當然可以用 gulp 、 webpack 、 grunt 等構建工具 壓縮、合併。

使用webpack壓縮js:

    plugins: [
        new UglifyJSPlugin(),    //打包後文件壓縮
    ]

如果是webpack4,可以直接使用:

 mode: 'production' 

用於生產環境,webpack會自動壓縮。

使用webpack壓縮css,

new OptimizeCSSAssetsPlugin({
    assetNameRegExp: /\.css\.*(?!.*map)/g,  //注意不要寫成 /\.css$/g
    cssProcessor: require('cssnano'),
    cssProcessorOptions: {
        discardComments: { removeAll: true },
        // 避免 cssnano 重新計算 z-index
        safe: true,
        // cssnano 集成了autoprefixer的功能
        // 會使用到autoprefixer進行無關字首的清理
        // 關閉autoprefixer功能
        // 使用postcss的autoprefixer功能
        autoprefixer: false
    },
    canPrint: true
}),

2、快取

快取這東西,第一次必須獲取到資源後,然後根據返回的資訊來告訴如何快取資源,可能採用的是強快取,也可能告訴客戶端瀏覽器是協商快取,這都需要根據響應的header內容來決定的。

瀏覽器快取包含兩種型別,即強快取(也叫本地快取)和協商快取,瀏覽器在第一次請求發生後,再次請求時:

  • 瀏覽器在請求某一資源時,會先獲取該資源快取的header資訊,判斷是否命中強快取(cache-control和expires資訊),若命中直接從快取中獲取資源資訊,包括快取header資訊;本次請求根本就不會與伺服器進行通訊;在firebug下可以檢視某個具有強快取資源返回的資訊,例如本地firebug檢視的一個強快取js檔案。
  • 如果沒有命中強快取,瀏覽器會發送請求到伺服器,請求會攜帶第一次請求返回的有關快取的header欄位資訊(Last-Modified/If-Modified-Since和Etag/If-None-Match),由伺服器根據請求中的相關header資訊來比對結果是否協商快取命中;若命中,則伺服器返回新的響應header資訊更新快取中的對應header資訊,但是並不返回資源內容,它會告知瀏覽器可以直接從快取獲取;否則返回最新的資源內容

強快取與協商快取的區別,可以用下表來進行描述:

獲取資源形式 狀態碼 傳送請求到伺服器
強快取  從快取取  200(from cache) 否,直接從快取取
協商快取  從快取取  304(not modified) 是,正如其名,通過伺服器來告知快取是否可用

1、強快取

強快取是直接從快取中獲取資源而不經過伺服器;與強快取相關的header欄位有兩個:

1)expires

當客戶端第一次訪問一個檔案資源的時候,服務端在返回資源內容的同時也返回了:

Expires: Mon, 1 Aug 2016 22:43:02 GMT

也就是服務端告訴瀏覽器,先把這個檔案快取起來,在這個過期時間之前,該檔案都不會變化了。

下一次瀏覽器又要訪問這個資源,並且訪問的時間在Mon, 1 Aug 2016 22:43:02 GMT之前,那瀏覽器就不去伺服器那邊獲取檔案了,而是直接從快取中取檔案。

2)Cache-Control

由於Expires給定的是絕對時間,而客戶端的系統時間可以由使用者任意修改,比如Expires設定的過期時間是

Mon, 1 Aug 2016 22:43:02 GMT

現在使用者把系統時間改為

Tue, 2 Aug 2016 22:43:02 GMT

則快取會被判為過期(雖然實際上還沒到那個時間)。因此在HTTP1.1中引入了Cache-Control,這就是一個相對時間,比如

Cache-Control: max-age=80

那就是說這份快取的有效期是80秒,而沒有給定過期的絕對時間。

由於Cache-Control是HTTP1.1中才有的,因此可能會有Expires和Cache-Control同時出現的情況,這時以Cache-Control為準。

2、協商快取

協商快取都是由伺服器來確定快取資源是否可用的,所以客戶端與伺服器端要通過某種標識來進行通訊,從而讓伺服器判斷請求資源是否可以快取訪問,這主要涉及到下面兩組header欄位,這兩組搭檔都是成對出現的,即第一次請求的響應頭帶上某個欄位(Last-Modified或者Etag),則後續請求則會帶上對應的請求欄位(If-Modified-Since或者If-None-Match),若響應頭沒有Last-Modified或者Etag欄位,則請求頭也不會有對應的欄位

1)Last-Modified/If-Modified-Since

  • 瀏覽器第一次跟伺服器請求一個資源,伺服器在返回這個資源的同時,在respone的header加上Last-Modified的header,這個header表示這個資源在伺服器上的最後修改時間
     
  • 瀏覽器再次跟伺服器請求這個資源時,在request的header上加上If-Modified-Since的header,這個header的值就是上一次請求時返回的Last-Modified的值
     
  • 伺服器再次收到資源請求時,根據瀏覽器傳過來If-Modified-Since和資源在伺服器上的最後修改時間判斷資源是否有變化,如果沒有變化則返回304 Not Modified,但是不會返回資源內容;如果有變化,就正常返回資源內容。當伺服器返回304 Not Modified的響應時,response header中不會再新增Last-Modified的header,因為既然資源沒有變化,那麼Last-Modified也就不會改變,這是伺服器返回304時的response header
     
  • 瀏覽器收到304的響應後,就會從快取中載入資源
     
  • 如果協商快取沒有命中,瀏覽器直接從伺服器載入資源時,Last-Modified的Header在重新載入的時候會被更新,下次請求時,If-Modified-Since會啟用上次返回的Last-Modified值

2)Etag/If-None-Match

這兩個值是由伺服器生成的每個資源的唯一標識字串,只要資源有變化就這個值就會改變;其判斷過程與Last-Modified/If-Modified-Since類似,與Last-Modified不一樣的是,當伺服器返回304 Not Modified的響應時,由於ETag重新生成過,response header中還會把這個ETag返回,即使這個ETag跟之前的沒有變化。

Last-Modified與ETag是可以一起使用的,伺服器會優先驗證ETag,一致的情況下,才會繼續比對Last-Modified,最後才決定是否返回304