前端緩存那些事

前端緩存那些事


前端緩存指的是,瀏覽器對服務器最近請求過的資源進行存儲,通過這種方式來達到減少與服務器的交互請求,以此減少對帶寬流量的浪費,以及減少了服務器的負擔,而瀏覽器緩存主要分為兩種,強緩存和協商緩存

1.強緩存

強緩存所謂的“強”,在於強制讓瀏覽器按照一定時間範圍內來存儲來自服務器的資源,有點強制的味道~,強緩存是利用Expires或者Cache-Control,不發送請求,直接從緩存中取,請求狀態碼會返回200(from cache)

1.1 Expires(已逐步淘汰)

Expires是HTTP/1.0中提及的,讓服務器為文件資源設置一個過期時間,在多長時間內可以將這些內容視為最新的,允許客戶端在這個時間之前不去檢查,MDN 具體介紹 點此

  • 指定到期時間

指定緩存到期GMT的絕對時間,如果expires到期需要重新請求

<code>Expires:Sat, 09 Jun 2020 08:13:56 GMT
複製代碼/<code>

1.2 Cache-Control(主要)

相比上一小節講的 expires,兩者有什麼區別呢? Cache-Control 你可以理解成為高級版expires,為了彌補Expires的缺陷在Http1.1協議引入的,且強大之外優先級也更高,也就是當Expires和Cache-Control同時存在時,Cache-Control 會覆蓋Expires的配置,即Cache-Control ( Http 1.1 ) > Expires ( Http 1.0 )

Cache-Control 比Expires比較要內涵,具備更多的屬性,其中包括如下

• no-cache :可以在本地緩存,可以在代理服務器緩存,需要先驗證才可使用緩存

• no-store : 禁止瀏覽器緩存,只能通過服務器獲取

• max-age : 設置資源的過期時間(效果與expires一樣)

例子演示:

<code>// 設置緩存時間為1年
Cache-Control: max-age=31536000
Expires:Sat, 09 Jun 2020 08:13:56 GMT //同時設置兩個,Expires會失效
複製代碼/<code>

則意味著瀏覽器可以緩存一年的時間,無需請求服務器,同時如果同時聲明Expires和Cache-Control,Expires將失效

️你可能會有疑惑Cache-Control no-cache與max-age=0有什麼區別?

本質上就是你按瀏覽器刷新與強制刷新的區分,看下一節

1.3 用戶對瀏覽器的操作

相信你離不開的操作就是F5(刷新按鈕),但是不同的刷新操作意味著不同的反應

• Ctrl + F5 (強制刷新)::request header多了cache-control: no-cache (重新獲取請求)

• F5 (刷新)/ctrl+R刷新::request header多了 cache-control: max-age=0 (需要先驗證才可使用緩存,Expires無效)

2.協商緩存

協商緩存,就沒有強緩存那麼霸道,協商緩存需要客戶端和服務端兩端進行交互,通過服務器告知瀏覽器緩存是否可用,並增加緩存標識,“有事好好商量”,兩者都會互相協商。 協商緩存,其實就是服務器與瀏覽器交互過程,一般有兩個回合,而協商主要有以下幾種方式:

2.1 Last-Modified (Http 1.0)

• 第一回合:當瀏覽器第一次請求服務器資源時,服務器通過Last-Modified 來設置響應頭的緩存標識,把資源最後修改的時間作為值寫入,再將資源返回給瀏覽器

• 第二回合:第二次請求時,瀏覽器會帶上 If-Modified-Since 請求頭去訪問服務器,服務器將 If-Modified-Since 中攜帶的時間與資源修改的時間對比,當時間不一致時,意味更新了,服務器會返回新資源並更新Last-Modified,當時間一致時,意味著資源沒有更新,服務器會返回304狀態碼,瀏覽器將從緩存中讀取資源

<code>//response header 第一回合
Last-Modified: Wed, 21 Oct 2019 07:28:00 GMT

//request header 第二回合
If-Modified-Since: Wed, 21 Oct 2019 07:29:00 GMT
複製代碼/<code>

2.2 Etag (Http 1.1)

MDN中提到ETag 之間的比較,使用的是強比較算法,即只有在每一個字節都相同的情況下,才可以認為兩個文件是相同的,而這個hash值,是由對文件的索引節、大小和最後修改時間進行Hash後得到的,而且要注意的是分佈式系統不適用,瞭解更多點我

• 第一回合: 也是跟上文一樣,瀏覽器去請求服務器資源,不過這次不是通過Last-Modified了,而是用Etag來設置響應頭緩存標識。Etag是由服務端生成的,然後瀏覽器會將Etag與資源緩存

• 第二回合: 瀏覽器會將 Etag 放入 If-None-Match 請求頭中去訪問服務器,服務器收到後,會對比兩端的標識,當兩者不一致時,意味著資源更新,會從服務器的響應讀取資源並更新Etag,瀏覽器將從緩存中讀取資源,當兩者一致時,意味著資源沒有更新,服務器會返回304狀態碼,瀏覽器將從緩存中讀取資源

<code>//response header 第一回合
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"

//request header 第二回合
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
複製代碼/<code>

對比完 Last-Modified 與 Etag,我們可以很顯然看到,協商緩存每次請求都會與服務器發生“關係”,第一回合都是拿數據和標識,而第二回合就是瀏覽器“諮詢”服務器是否資源已經更新的過程。

同時,如果以上兩種方式同時使用,Etag 優先級會更高,即 Etag( Http 1.1 ) > Last-Modified ( Http 1.0 )

3.緩存狀態碼

3.1 狀態碼200 OK(from cache)

這是瀏覽器沒有跟服務器確認,直接用了瀏覽器緩存,性能最好的,沒有網絡請求,那麼什麼情況會出現這種情況?一般在expires或者 Cache-Control 中的max-age頭部有效時會發生

3.2 狀態碼304 Not Modified

是瀏覽器和服務器“交流”了,確定使用緩存後,再用緩存,也就是第二節講的通過Etag或Last-Modified的第二回閤中對比,對比兩者一致,則意味資源不更新,則服務器返回304狀態碼

3.3 狀態碼 200

以上兩種緩存全都失敗,也就是未緩存或者緩存未過期,需要瀏覽器去獲取最新的資源,效率最低 一句話:緩存是否過期用:Cache-Control(max-age), Expires,緩存是否有效用:Last-Modified,Etag

4.緩存的應用

講述緩存在我們開發中最常見的使用

4.1 Vue中緩存的應用

• keepAlive

vue官方文檔提到,當在這些組件之間切換的時候,你有時會想保持這些組件的狀態,以避免反覆重渲染導致的性能問題,這個時候我們希望那些標籤的組件實例能夠被在它們第一次被創建的時候緩存下來,我們可以用一個 元素將其動態組件包裹起來 官方文檔

主要用於保留組件狀態或避免重新渲染,也意味著不會再走mounted,beforeDestroy函數,組件將被緩存,不用銷燬重新渲染,性能比較好

路由的選擇性緩存

<code>// router.js
export default new Router({
routes:[
{ path: '/test',
name: 'test',
component: () => import('@/views/test/test.vue'),
meta: {
title: '測試',
keepAlive: true
}
},

// App.vue
<keep-alive>
<router-view>

/<keep-alive>
<router-view>
複製代碼/<code>

組件緩存

<code> <keep-alive>
<component>
/<keep-alive>
複製代碼/<code>
  • 打包加入hash

前端工程化開發,可以使用 Webpack 編譯,打包的資源文件路徑裡自動帶有一串隨機字符串,稱為 hash

在vue cli腳手架中,我們可以通過配置vue.config.js(本質上是配置webpack)來設置編譯生成的文件具備hash值,意味著每次打包編譯的文件都是唯一的,來防止因為緩存,導致資源沒有更新,官方文檔

Vue-Cli 3x版本

<code>// vue.config.js
module.exports = {
filenameHashing: true,
chainWebpack: (config) => {
config.output.filename('[name].[hash].js').end();
}
}
複製代碼/<code>

4.2 Nginx的緩存

• 配置expires

假設我想通過web應用的圖片緩存一週,那你可以在nginx中配置如下,配置完之後一週之內的資源只會訪問瀏覽器的資源,而不是去請求Nginx

<code> location ~ \\.(gif|jpg|jpeg|png)$ {
root /var/mywww/html/public/
expires 7d; //表示把數據緩存7天,d:天,s:秒,m:分
}
複製代碼/<code>
  • 設置 etag
<code> location ~ \\.(gif|jpg|jpeg|png)$ {
root /var/mywww/html/public/
etag\t\toff; // 默認是開啟 on
}/<code>


作者:樹醬
鏈接:https://juejin.im/post/5e7ef4a9e51d4546f8784b21
來源:掘金
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。


分享到:


相關文章: