前端面試八股文之瀏覽器緩存

這一題應(yīng)該也是很容易碰到的。
首先要說明下瀏覽器緩存只是web緩存體系中的一小個
圖:

然后我們得知道緩存的是什么東西:HTML文檔、圖片、CSS和JS等文件。對于一些不經(jīng)常變的內(nèi)容,瀏覽器會將他們保存在本地的文件中,下次訪問相同網(wǎng)站的時候,直接加載這些資源,加速訪問。
這些被瀏覽器保存的文件就被稱為緩存(不是指Cookie或者Localstorage)。
面試官可能會問:為什么需要瀏覽器緩存?
答:
盡量拿瀏覽器本地緩存的數(shù)據(jù),降低帶寬消耗。
不需要每次都從服務(wù)器拿數(shù)據(jù),降低服務(wù)器壓力。
減少等待時間,提升用戶體驗感。
問完作用后會開始問你有哪些緩存方法呢?
答:
強緩存。
協(xié)商緩存。
然后面試官會讓你分別解釋下或者說下瀏覽器緩存機制等。
在這之前我們得知道能否緩存以及緩存多久都是由服務(wù)器來定義的,通過設(shè)置響應(yīng)頭的幾個關(guān)鍵屬性。
我們將會接觸到的幾個header的屬性:
Cache-Control
Expires(存在問題,http1.0遺物)
Last-Modified
Etag
If-None-Match
If-Modified-Since
1. 強緩存
由服務(wù)器設(shè)置兩個屬性:Expires以及Cache-Control。
服務(wù)器在返回數(shù)據(jù)時會發(fā)送Expires以及Cache-Control來通知瀏覽器我是要緩存。
那么瀏覽器在下次請求時會先判斷是否符合Expires以及Cache-Control,如果滿足則直接從本地獲取數(shù)據(jù)。
其中Expires是通過絕對時間來判斷的,當(dāng)瀏覽器判斷時間在Expires設(shè)置的時間之前,就滿足緩存條件,直接從本地獲取數(shù)據(jù)。但這也存在弊端,當(dāng)用戶修改客戶端時間時緩存可能就會失效。因此后面多用Cache-Control來配合Expires設(shè)置緩存。
Cache-Control具有以下屬性:
max-age=xxx:緩存的內(nèi)容將在 xxx 秒后失效,這個時間是個時間間隔相對時間。
public:所有內(nèi)容都將被緩存(客戶端和代理服務(wù)器都可緩存)
private:內(nèi)容只緩存到私有緩存中(僅客戶端可以緩存,代理服務(wù)器不可緩存)
no-cache:必須先與服務(wù)器確認返回的響應(yīng)是否被更改,然后才能使用該響應(yīng)來滿足后續(xù)對同一個網(wǎng)址的請求。因此,如果存在合適的驗證令牌(ETag),no-cache 會發(fā)起往返通信來驗證緩存的響應(yīng),如果資源未被更改,可以避免下載
no-store:所有內(nèi)容都不會被緩存或 Internet 臨時文件中
must-revalidation/proxy-revalidation:如果緩存的內(nèi)容失效,請求必須發(fā)送到服務(wù)器/代理以進行重新驗證
其中max-age是設(shè)置的一段時間間隔,不會涉及到日期,因此不存在Expires中的問題。
Cache-Control優(yōu)先級高于Expires。

2. 協(xié)商緩存
既然有了強緩存,為什么還要協(xié)商緩存呢?
答:強緩存所設(shè)置的時間不能是太長,太長了會發(fā)生數(shù)據(jù)更新了但依舊在展示舊數(shù)據(jù)的問題。如果強緩存失效了,那么每次請求都一定會返回數(shù)據(jù),不管數(shù)據(jù)是否發(fā)生了改變,這會造成不必要的服務(wù)器壓力。
什么情況下會走協(xié)商緩存呢?
當(dāng)然是在強緩存不滿足的情況。
曾經(jīng)被問到一個問題,為什么有協(xié)商緩存一定會有強緩存呢?
答:如果沒有強緩存只有協(xié)商緩存,那么就不會有數(shù)據(jù)緩存在瀏覽器中,并且每次請求都會發(fā)送兩次造成嚴重浪費。
當(dāng)瀏覽器發(fā)現(xiàn)超出Cache-Control的時間間隔時會向服務(wù)器發(fā)送請求,此時的請求只是告訴服務(wù)器強緩存失效了,詢問服務(wù)器是否需要更新資源。
此時是否需要更新看服務(wù)器那邊的情況,如果需要更新,瀏覽器會再發(fā)送一次請求告訴服務(wù)器他所需要的數(shù)據(jù),服務(wù)器會發(fā)送數(shù)據(jù)給瀏覽器,然后再次緩存數(shù)據(jù)。
如果服務(wù)器通知不需要更新(返回304Not Modified),那么瀏覽器會直接從本地拿緩存。
那么通過什么來讓服務(wù)器判斷是否需要更新數(shù)據(jù)呢?
答:服務(wù)器在發(fā)送數(shù)據(jù)時會在響應(yīng)頭中添加Last-Modified以及Etag,瀏覽器在協(xié)商緩存過程中會在請求頭中添加If-Modified-Since以及If-None-Match傳給服務(wù)器,讓服務(wù)器判斷是否需要更新。
其中
Last-Modified為最后一次更新的時間,時間精度為秒。
Last-Modified-Since就是瀏覽器緩存數(shù)據(jù)時的Last-Modified。
Etag為一段字符串,每個文件都有屬于自己的字符串,(分布式系統(tǒng)中會導(dǎo)致每個文件都有不同的Etag讓緩存失效)。
If-None-Match為緩存時的Etag字符串。
Last-Modified和If-Modified-Since兩個是HTTP1.0的屬性
Etag和If-None-Match是HTTP1.1中引入的新屬性
Etag優(yōu)先級高于Last-Modified
其中面試官可能會問你為什么要在HTTP1.1引入Etag和If-None-Match?
答:前面說過Last-Modified時間精度為秒,那么就可能存在服務(wù)器文件修改了(在更小的時間間隔內(nèi)改變),但是時間卻沒變的問題。而Etag使用的是唯一標(biāo)識符,一段字符串。當(dāng)文件改動時會立即更新Etag,因此不會有上述問題。
3. 瀏覽器緩存機制
1)瀏覽器在加載資源時,先根據(jù)這個資源的一些http header判斷它是否命中強緩存,強緩存如果命中,瀏覽器直接從自己的緩存中讀取資源,不會發(fā)請求到服務(wù)器。比如:某個css文件,如果瀏覽器在加載它所在的網(wǎng)頁時,這個css文件的緩存配置命中了強緩存,瀏覽器就直接從緩存中加載這個css,連請求都不會發(fā)送到網(wǎng)頁所在服務(wù)器;
2)當(dāng)強緩存沒有命中的時候,瀏覽器一定會發(fā)送一個請求到服務(wù)器,通過服務(wù)器端依據(jù)資源的另外一些http header驗證這個資源是否命中協(xié)商緩存,如果協(xié)商緩存命中,服務(wù)器會將這個請求返回,但是不會返回這個資源的數(shù)據(jù),而是告訴客戶端可以直接從緩存中加載這個資源,于是瀏覽器就又會從自己的緩存中去加載這個資源;
3)強緩存與協(xié)商緩存的共同點是:如果命中,都是從客戶端緩存中加載資源,而不是從服務(wù)器加載資源數(shù)據(jù);區(qū)別是:強緩存不發(fā)請求到服務(wù)器,協(xié)商緩存會發(fā)請求到服務(wù)器。
4)當(dāng)協(xié)商緩存也沒有命中的時候,瀏覽器直接從服務(wù)器加載資源數(shù)據(jù)。
圖:

其實前端可以通過設(shè)置meta標(biāo)簽控制緩存,但兼容性不好
// 必須是 GMT 格式?
<meta http-equiv="expires" content="Fri,12 Jan 2001 15:15:15 GMT">
// 是否設(shè)置緩存?
<meta http-equiv="pragma" content="no-cache">
不足之處麻煩指出,謝謝!
整理自:
https://www.jianshu.com/p/7531c98a6933
https://www.cnblogs.com/keeperdog/p/11498918.html
https://segmentfault.com/a/1190000017553812
侵刪。