解析瀏覽器端的AJAX緩存機(jī)制
AJAX的緩存是由瀏覽器維持的,對(duì)于發(fā)向服務(wù)器的某個(gè)url,ajax僅在第一次請(qǐng)求時(shí)與服務(wù)器交互信息,之后的請(qǐng)求中,ajax不再向服務(wù)器提交請(qǐng)求,而是直接從緩存中提取數(shù)據(jù)。
有些情況下,我們需要每一次都從服務(wù)器得到更新后數(shù)據(jù)。思路是讓每次請(qǐng)求的url都不同,而又不影響正常應(yīng)用:在url之后加入隨機(jī)內(nèi)容。
e.g.
url=url+"&"+Math.random();
Key points:
1.每次請(qǐng)求的url都不一樣(ajax的緩存便不起作用)
2.不影響正常應(yīng)用(最基本的)
這里我們由兩條結(jié)論:
1:Ajax的緩存和HTTP的緩存是一樣的
現(xiàn)代瀏覽器的HTTP和緩存機(jī)制比Ajax的XMLHttpRequest對(duì)象要差很多,所以它不認(rèn)識(shí)也不關(guān)心Ajax請(qǐng)求.它僅僅是遵循普通的HTTP緩存規(guī)則,通過服務(wù)器返回的響應(yīng)頭來進(jìn)行緩存.
如果你已經(jīng)對(duì) HTTP緩存 有了解,那么你可以把HTTP緩存的知識(shí)用對(duì)Ajax緩存的理解上. 他們只有一點(diǎn)不同的,就是設(shè)置響應(yīng)頭的方式會(huì)和普通文件不一樣.
下面這些響應(yīng)頭可以讓你的Ajax可緩存:
Expires: 這一項(xiàng)應(yīng)該被設(shè)置成未來的某個(gè)合適的時(shí)間點(diǎn),時(shí)間點(diǎn)的設(shè)置取決于內(nèi)容變動(dòng)的頻繁程度.舉個(gè)栗子,如果請(qǐng)求的是個(gè)庫存數(shù)量,那么Expires的值可以是10秒以后.如果請(qǐng)求的是一個(gè)相片,那么Expires的值就可以久一點(diǎn),因?yàn)樗粫?huì)經(jīng)常變動(dòng).Expires頭可以讓瀏覽器在一段時(shí)間內(nèi)重用本地緩存數(shù)據(jù),從而避免任何不必要的與服務(wù)器數(shù)據(jù)交互.
Last-Modified: 設(shè)置這一項(xiàng)是一個(gè)很好的選擇,通過它,瀏覽器在發(fā)送條件性GET請(qǐng)求的時(shí)候會(huì)使用請(qǐng)求頭里的 If-Modified-Since 來檢查本地緩存的內(nèi)容.如果數(shù)據(jù)不需要更新,服務(wù)器會(huì)返回304響應(yīng)狀態(tài).
Cache-Control: 在合適的情況下,這個(gè)值應(yīng)該被設(shè)置為 Public ,這樣所有的中間代理和緩存都可以被保存并且與其他用戶共享內(nèi)容.在火狐里,它還支持HTTPS請(qǐng)求的緩存
當(dāng)然,如果你使用POST方式發(fā)送Ajax是不能緩存的,因?yàn)镻OST請(qǐng)求永遠(yuǎn)不會(huì)被緩存.如果你的Ajax請(qǐng)求會(huì)產(chǎn)生其他作用(比如銀行賬戶之間的轉(zhuǎn)賬),請(qǐng)使用POST請(qǐng)求.
我們?cè)O(shè)置了一個(gè)demo(這個(gè)demo已經(jīng)不能看了ヽ(≧□≦)ノ)來闡明這些頭信息是如何工作的. 在HttpWatch里,你可以看到我們?cè)陧憫?yīng)頭信息里設(shè)置了以上三個(gè)響應(yīng)頭

如果你規(guī)律的點(diǎn)擊 ‘Ajax Update' 按鈕,時(shí)間的改變會(huì)趨向于每隔一分鐘一次.因?yàn)镋xpires響應(yīng)頭被設(shè)置為未來的一分鐘.在下面這張截圖里你可以看到:重復(fù)的點(diǎn)擊更新按鈕時(shí),Ajax請(qǐng)求會(huì)讀取瀏覽器本地的緩存而不會(huì)產(chǎn)生網(wǎng)絡(luò)活動(dòng)(發(fā)送和傳輸欄的值都是0)

最后一次1:06.531時(shí)刻的點(diǎn)擊發(fā)送的Ajax請(qǐng)求產(chǎn)生了網(wǎng)絡(luò)數(shù)據(jù)傳輸,因?yàn)榫彺娴臄?shù)據(jù)已經(jīng)超過了一分鐘. 服務(wù)器返回200響應(yīng)狀態(tài)表示獲取到了一份新的數(shù)據(jù).
猜測(cè)這個(gè)demo應(yīng)該是一個(gè)按鈕,每點(diǎn)擊一次獲取一次當(dāng)前時(shí)間然后回現(xiàn)在頁面上.
2:IE瀏覽器在Expires時(shí)間過期之前不會(huì)刷新通過Ajax獲取的內(nèi)容.
有些時(shí)候,Ajax在頁面加載的時(shí)候就被用來填充頁面的某些部分(比如一個(gè)價(jià)格列表).它并不是通過用戶的某個(gè)事件(比如點(diǎn)擊某個(gè)按鈕)觸發(fā)的,而是在頁面加載的時(shí)候就通過javascript來發(fā)送的.就好像Ajax請(qǐng)求和那些嵌入資源(比如js和css)是一樣的.
如果你開發(fā)這樣的頁面,在刷新它的時(shí)候,很可能想要更新嵌入的Ajax請(qǐng)求內(nèi)容.對(duì)于嵌入資源(CSS文件,圖片等),瀏覽器會(huì)通過用戶刷新的方式是F5(刷新)還是Ctrl+F5(強(qiáng)制刷新)來自動(dòng)發(fā)送下列不同類型的請(qǐng)求:
1.F5(刷新): 如果請(qǐng)求內(nèi)容帶有 Last-Modified 響應(yīng)頭,那么瀏覽器會(huì)發(fā)送條件性更新請(qǐng)求. 它使用 If-Modified-Since 請(qǐng)求頭進(jìn)行比較,這樣服務(wù)器就可以返回304狀態(tài)來避免傳輸不必要的數(shù)據(jù).
2.Ctrl+F5(強(qiáng)制刷新): 告訴瀏覽器發(fā)送無條件更新請(qǐng)求,請(qǐng)求頭的 Cache-Control 被設(shè)置為‘no-cache'.這告訴所有的中間代理和緩存:瀏覽器需要獲取最新的版本,無論它是否已經(jīng)被緩存.
Firefox把這個(gè)刷新的方式傳播到了那些在頁面加載的時(shí)候就發(fā)送的Ajax請(qǐng)求上,把這些Ajax請(qǐng)求當(dāng)成嵌入資源來處理.下面是HttpWatch在火狐下的截圖,顯示了Ajax Caching demo(這個(gè)demo已經(jīng)不能看了ヽ(≧□≦)ノ)刷新(F5)頁面時(shí)Ajax請(qǐng)求的效果:

火狐確保Ajax發(fā)起的請(qǐng)求是條件性的.在這個(gè)例子里,如果緩存數(shù)據(jù)不到10秒,服務(wù)器返回304,超過10秒,服務(wù)器返回200,重新傳送數(shù)據(jù).
在ie里,加載頁面時(shí)就發(fā)起的Ajax請(qǐng)求被看做是和頁面其他部分刷新毫無關(guān)系的,也不會(huì)被用戶的刷新方式所左右.如果緩存的ajax數(shù)據(jù)沒有過期,就不會(huì)有GET請(qǐng)求發(fā)送到服務(wù)器.它會(huì)直接從緩存里讀取數(shù)據(jù),從HttpWatch里看就是(Cache)結(jié)果.下面這個(gè)圖是在ie下緩存沒有過期的情況下按F5刷新:

就算是通過 Ctrl+F5 強(qiáng)制刷新,通過Ajax獲取的數(shù)據(jù)也是從緩存里讀取:

這就意味著,任何通過Ajax得到的內(nèi)容如果沒有過期,在ie下都不會(huì)被更新 - 即使你使用Ctrl+F5強(qiáng)制刷新. 唯一能確保你獲取最新數(shù)據(jù)的方法就是手動(dòng)清楚緩存. 可以使用HttpWatch的工具欄:

注意,Cache結(jié)果和304結(jié)果是不同的.Cache其實(shí)是200(cache),304就是304.Cache其實(shí)沒有向服務(wù)器發(fā)送請(qǐng)求,可以從chrome里看到,它的耗時(shí)是0,response也是空.而304不同,
304請(qǐng)求是瀏覽器發(fā)起了一個(gè)條件性的請(qǐng)求,這個(gè)請(qǐng)求攜帶了 If-Modified-Since 請(qǐng)求頭,如果這個(gè)文件在瀏覽器發(fā)送的這個(gè)時(shí)間之后沒有修改過,服務(wù)器端就回返回一個(gè)304狀態(tài),告訴瀏覽器使用它本地的緩存內(nèi)容.它沒有Cache快,因?yàn)檎?qǐng)求還是發(fā)送到了服務(wù)器端,只不過服務(wù)器端沒有發(fā)送數(shù)據(jù).
可以看下taobao首頁,里面既有200(cache)也有304.可以查看他們的區(qū)別.
總結(jié):
我們都知道,ajax能提高頁面載入的速度的主要原因是通過ajax減少了重復(fù)數(shù)據(jù)的載入,真正做到按需獲取,既然如此,我們?cè)趯慳jax程序的時(shí)候不妨送佛送到西,在客戶端再做一次緩存,進(jìn)一步提高數(shù)據(jù)載入速度。那就是在載入數(shù)據(jù)的同時(shí)將數(shù)據(jù)緩存在瀏覽器內(nèi)存中,一旦數(shù)據(jù)被載入,只要頁面未刷新,該數(shù)據(jù)就永遠(yuǎn)的緩存在內(nèi)存中,當(dāng)用戶再次查看該數(shù)據(jù)時(shí),則不需要從服務(wù)器上去獲取數(shù)據(jù),極大的降低了服務(wù)器的負(fù)載和提高了用戶的體驗(yàn)。
相關(guān)文章
javascript函數(shù)定義的幾種區(qū)別小結(jié)
本篇文章主要是對(duì)javascript函數(shù)定義的幾種區(qū)別進(jìn)行了詳細(xì)的總結(jié)介紹,需要的朋友可以過來參考下,希望對(duì)大家有所幫助2014-01-01
egg.js的基本使用和調(diào)用數(shù)據(jù)庫的方法示例
這篇文章主要介紹了egg.js的基本使用和調(diào)用數(shù)據(jù)庫的方法示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05
JavaScript實(shí)現(xiàn)樹的遍歷算法示例【廣度優(yōu)先與深度優(yōu)先】
這篇文章主要介紹了JavaScript實(shí)現(xiàn)樹的遍歷算法,結(jié)合實(shí)例形式分析了javascript針對(duì)樹結(jié)構(gòu)的廣度優(yōu)先遍歷與深度優(yōu)先遍歷實(shí)現(xiàn)方法,需要的朋友可以參考下2017-10-10
js實(shí)現(xiàn)select二級(jí)聯(lián)動(dòng)下拉菜單
這個(gè)是簡(jiǎn)單也是最基本的下拉框聯(lián)動(dòng)的示例,這個(gè)示例主要針對(duì)那些只有二級(jí)聯(lián)動(dòng),且第一級(jí)是固定的選項(xiàng),第二級(jí)的內(nèi)容也比較簡(jiǎn)單,不刷新的聯(lián)動(dòng),感興趣的小伙伴們可以參考一下2016-04-04
js 模擬實(shí)現(xiàn)類似c#下的hashtable的簡(jiǎn)單功能代碼
越來越感覺js對(duì)集合的處理沒有c#強(qiáng)大。比如在實(shí)際開發(fā)中,經(jīng)常用到在一維數(shù)組或者二維數(shù)組里取某一個(gè)滿足某些條件的項(xiàng),通常的處理方式就是遍歷數(shù)組,對(duì)比條件,匹配就取出,然后結(jié)束循環(huán)。2010-01-01
JavaScript?中?this?關(guān)鍵字的作用及改變其上下文的方法
這篇文章主要介紹了JavaScript?中?this?關(guān)鍵字的作用和如何改變其上下文,通過使用?call,?apply,?bind?方法,可以改變函數(shù)中的?this?指向,從而在不同的上下文中使用同一個(gè)函數(shù),需要的朋友可以參考下2023-01-01
詳解addEventListener的三個(gè)參數(shù)之useCapture
本文主要給大家介紹的是addEventListener的三個(gè)參數(shù)之中的useCapture參數(shù)的使用及示例分享,有需要的小伙伴參考下2015-03-03
使用javascript函數(shù)編寫簡(jiǎn)單銀行取錢存錢流程
本文通過實(shí)例代碼給大家講解了使用javascript函數(shù)編寫簡(jiǎn)單銀行取錢存錢流程,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2018-05-05
20多個(gè)小事例帶你重溫ES10新特性(小結(jié))
這篇文章主要介紹了20多個(gè)小事例帶你重溫ES10新特性(小結(jié)),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
漂亮的widgets,支持換膚和后期開發(fā)新皮膚(2007-4-27已更新1.7alpha)
漂亮的widgets,支持換膚和后期開發(fā)新皮膚(2007-4-27已更新1.7alpha)...2007-04-04

