前端緩存那些事
?前端緩存指的是,瀏覽器對(duì)服務(wù)器最近請(qǐng)求過的資源進(jìn)行存儲(chǔ),通過這種方式來達(dá)到減少與服務(wù)器的交互請(qǐng)求,以此減少對(duì)帶寬流量的浪費(fèi),以及減少了服務(wù)器的負(fù)擔(dān),而瀏覽器緩存主要分為兩種,強(qiáng)緩存和協(xié)商緩存
?

1.強(qiáng)緩存
?強(qiáng)緩存所謂的“強(qiáng)”,在于強(qiáng)制讓瀏覽器按照一定時(shí)間范圍內(nèi)來存儲(chǔ)來自服務(wù)器的資源,有點(diǎn)強(qiáng)制的味道~,強(qiáng)緩存是利用Expires或者Cache-Control,不發(fā)送請(qǐng)求,直接從緩存中取,請(qǐng)求狀態(tài)碼會(huì)返回200(from cache)
?
1.1 Expires(已逐步淘汰)
?Expires是HTTP/1.0中提及的,讓服務(wù)器為文件資源設(shè)置一個(gè)過期時(shí)間,在多長(zhǎng)時(shí)間內(nèi)可以將這些內(nèi)容視為最新的,允許客戶端在這個(gè)時(shí)間之前不去檢查,MDN 具體介紹 點(diǎn)此
?
指定到期時(shí)間
指定緩存到期GMT的絕對(duì)時(shí)間,如果expires到期需要重新請(qǐng)求
Expires:Sat, 09 Jun 2020 08:13:56 GMT
1.2 Cache-Control(主要)
?相比上一小節(jié)講的 expires,兩者有什么區(qū)別呢?Cache-Control 你可以理解成為高級(jí)版expires,為了彌補(bǔ)Expires的缺陷在Http1.1協(xié)議引入的,且強(qiáng)大之外優(yōu)先級(jí)也更高,也就是當(dāng)Expires和Cache-Control同時(shí)存在時(shí),Cache-Control 會(huì)覆蓋Expires的配置,即Cache-Control ( Http 1.1 ) > Expires ( Http 1.0 )
?
Cache-Control 比Expires比較要內(nèi)涵,具備更多的屬性,其中包括如下
? no-cache :可以在本地緩存,可以在代理服務(wù)器緩存,需要先驗(yàn)證才可使用緩存
? no-store :禁止瀏覽器緩存,只能通過服務(wù)器獲取
? max-age :設(shè)置資源的過期時(shí)間(效果與expires一樣)
例子演示:
// 設(shè)置緩存時(shí)間為1年
Cache-Control: max-age=31536000
Expires:Sat, 09 Jun 2020 08:13:56 GMT //同時(shí)設(shè)置兩個(gè),Expires會(huì)失效
則意味著瀏覽器可以緩存一年的時(shí)間,無需請(qǐng)求服務(wù)器,同時(shí)如果同時(shí)聲明Expires和Cache-Control,Expires將失效
????你可能會(huì)有疑惑Cache-Control no-cache與max-age=0有什么區(qū)別?
?
本質(zhì)上就是你按瀏覽器刷新與強(qiáng)制刷新的區(qū)分,看下一節(jié)
1.3 用戶對(duì)瀏覽器的操作
?相信你離不開的操作就是F5(刷新按鈕),但是不同的刷新操作意味著不同的反應(yīng)
?
? Ctrl + F5 (強(qiáng)制刷新)::request header多了cache-control:no-cache (重新獲取請(qǐng)求)
? F5 (刷新)/ctrl+R刷新::request header多了 cache-control:max-age=0 (需要先驗(yàn)證才可使用緩存,Expires無效)
2.協(xié)商緩存
?協(xié)商緩存,就沒有強(qiáng)緩存那么霸道,協(xié)商緩存需要客戶端和服務(wù)端兩端進(jìn)行交互,通過服務(wù)器告知瀏覽器緩存是否可用,并增加緩存標(biāo)識(shí),“有事好好商量”,兩者都會(huì)互相協(xié)商。協(xié)商緩存,其實(shí)就是服務(wù)器與瀏覽器交互過程,一般有兩個(gè)回合,而協(xié)商主要有以下幾種方式:
?
2.1 Last-Modified (Http 1.0)
? 第一回合:當(dāng)瀏覽器第一次請(qǐng)求服務(wù)器資源時(shí),服務(wù)器通過Last-Modified 來設(shè)置響應(yīng)頭的緩存標(biāo)識(shí),把資源最后修改的時(shí)間作為值寫入,再將資源返回給瀏覽器
? 第二回合:第二次請(qǐng)求時(shí),瀏覽器會(huì)帶上 If-Modified-Since 請(qǐng)求頭去訪問服務(wù)器,服務(wù)器將 If-Modified-Since 中攜帶的時(shí)間與資源修改的時(shí)間對(duì)比,當(dāng)時(shí)間不一致時(shí),意味更新了,服務(wù)器會(huì)返回新資源并更新Last-Modified,當(dāng)時(shí)間一致時(shí),意味著資源沒有更新,服務(wù)器會(huì)返回304狀態(tài)碼,瀏覽器將從緩存中讀取資源
//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
2.2 Etag (Http 1.1)
?MDN中提到ETag 之間的比較,使用的是強(qiáng)比較算法,即只有在每一個(gè)字節(jié)都相同的情況下,才可以認(rèn)為兩個(gè)文件是相同的,而這個(gè)hash值,是由對(duì)文件的索引節(jié)、大小和最后修改時(shí)間進(jìn)行Hash后得到的,而且要注意的是分布式系統(tǒng)不適用,了解更多點(diǎn)我
?
? 第一回合:也是跟上文一樣,瀏覽器去請(qǐng)求服務(wù)器資源,不過這次不是通過Last-Modified了,而是用Etag來設(shè)置響應(yīng)頭緩存標(biāo)識(shí)。Etag是由服務(wù)端生成的,然后瀏覽器會(huì)將Etag與資源緩存
? 第二回合: 瀏覽器會(huì)將 Etag 放入 If-None-Match 請(qǐng)求頭中去訪問服務(wù)器,服務(wù)器收到后,會(huì)對(duì)比兩端的標(biāo)識(shí),當(dāng)兩者不一致時(shí),意味著資源更新,會(huì)從服務(wù)器的響應(yīng)讀取資源并更新Etag,瀏覽器將從緩存中讀取資源,當(dāng)兩者一致時(shí),意味著資源沒有更新,服務(wù)器會(huì)返回304狀態(tài)碼,瀏覽器將從緩存中讀取資源
//response header 第一回合
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
//request header 第二回合
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
對(duì)比完 Last-Modified 與 Etag,我們可以很顯然看到,協(xié)商緩存每次請(qǐng)求都會(huì)與服務(wù)器發(fā)生“關(guān)系”,第一回合都是拿數(shù)據(jù)和標(biāo)識(shí),而第二回合就是瀏覽器“咨詢”服務(wù)器是否資源已經(jīng)更新的過程。
同時(shí),如果以上兩種方式同時(shí)使用,Etag 優(yōu)先級(jí)會(huì)更高,即 Etag( Http 1.1 ) > Last-Modified ( Http 1.0 )
3.緩存狀態(tài)碼
3.1 狀態(tài)碼200 OK(from cache)
?這是瀏覽器沒有跟服務(wù)器確認(rèn),直接用了瀏覽器緩存,性能最好的,沒有網(wǎng)絡(luò)請(qǐng)求,那么什么情況會(huì)出現(xiàn)這種情況?一般在expires或者 Cache-Control 中的max-age頭部有效時(shí)會(huì)發(fā)生
?
3.2 狀態(tài)碼304 Not Modified
?是瀏覽器和服務(wù)器“交流”了,確定使用緩存后,再用緩存,也就是第二節(jié)講的通過Etag或Last-Modified的第二回合中對(duì)比,對(duì)比兩者一致,則意味資源不更新,則服務(wù)器返回304狀態(tài)碼
?
3.3 狀態(tài)碼 200
?以上兩種緩存全都失敗,也就是未緩存或者緩存未過期,需要瀏覽器去獲取最新的資源,效率最低 一句話:緩存是否過期用:Cache-Control(max-age), Expires,緩存是否有效用:Last-Modified,Etag
?
4.緩存的應(yīng)用
?講述緩存在我們開發(fā)中最常見的使用
?
4.1 Vue中緩存的應(yīng)用
? keepAlive
?vue官方文檔提到,當(dāng)在這些組件之間切換的時(shí)候,你有時(shí)會(huì)想保持這些組件的狀態(tài),以避免反復(fù)重渲染導(dǎo)致的性能問題,這個(gè)時(shí)候我們希望那些標(biāo)簽的組件實(shí)例能夠被在它們第一次被創(chuàng)建的時(shí)候緩存下來,我們可以用一個(gè)
?元素將其動(dòng)態(tài)組件包裹起來 官方文檔??
主要用于保留組件狀態(tài)或避免重新渲染,也意味著不會(huì)再走mounted,beforeDestroy函數(shù),組件將被緩存,不用銷毀重新渲染,性能比較好
路由的選擇性緩存
// router.js
export default new Router({
routes:[
{ path: '/test',
name: 'test',
component: () => import('@/views/test/test.vue'),
meta: {
title: '測(cè)試',
keepAlive: true
}
},
// App.vue
<keep-alive v-if='$route.meta.keepAlive'>
<router-view></router-view>
</keep-alive>
<router-view v-if='!$route.meta.keepAlive'></router-view>
組件緩存
<keep-alive>
<component v-bind:is="currentTabComponent"></component>
</keep-alive>
打包加入hash
?前端工程化開發(fā),可以使用 Webpack 編譯,打包的資源文件路徑里自動(dòng)帶有一串隨機(jī)字符串,稱為 hash
?
在vue cli腳手架中,我們可以通過配置vue.config.js(本質(zhì)上是配置webpack)來設(shè)置編譯生成的文件具備hash值,意味著每次打包編譯的文件都是唯一的,來防止因?yàn)榫彺?,?dǎo)致資源沒有更新,官方文檔??
Vue-Cli 3x版本
// vue.config.js
module.exports = {
filenameHashing: true,
chainWebpack: (config) => {
config.output.filename('[name].[hash].js').end();
}
}
4.2 Nginx的緩存
? 配置expires
假設(shè)我想通過web應(yīng)用的圖片緩存一周,那你可以在nginx中配置如下??,配置完之后一周之內(nèi)的資源只會(huì)訪問瀏覽器的資源,而不是去請(qǐng)求Nginx
location ~ \.(gif|jpg|jpeg|png)$ {
root /var/mywww/html/public/
expires 7d; //表示把數(shù)據(jù)緩存7天,d:天,s:秒,m:分
}
設(shè)置 etag
location ~ \.(gif|jpg|jpeg|png)$ {
root /var/mywww/html/public/
etag off; // 默認(rèn)是開啟 on
}
更多的Nginx學(xué)習(xí),可以看我上一篇 前端Nginx那些事
請(qǐng)你喝杯?? 記得三連哦~
1.閱讀完記得給?? 醬點(diǎn)個(gè)贊哦,有?? 有動(dòng)力
2.關(guān)注公眾號(hào)前端那些趣事,陪你聊聊前端的趣事
3.文章收錄在Github frontendThings 感謝Star?
