對(duì)于緩存我們都已經(jīng)很熟悉了,緩存分為很多種,瀏覽器緩存、試圖緩存、服務(wù)器緩存、數(shù)據(jù)庫緩存等等一些,那今天我們先介紹一下視圖緩存和MemoryCache內(nèi)存緩存的概念和用法:
在老的版本的MVC里面,有一種可以緩存視圖的特性(OutputCache),可以保持同一個(gè)參數(shù)的請(qǐng)求,在N段時(shí)間內(nèi),直接從mvc的緩存中讀取,不去走視圖的邏輯。
在Asp.Net core 2.1中,官方文檔上稱:響應(yīng)緩存可減少客戶端或代理對(duì) web 服務(wù)器的請(qǐng)求數(shù)。 響應(yīng)緩存還可減少量工作的 web 服務(wù)器執(zhí)行程序生成響應(yīng)。 響應(yīng)緩存由標(biāo)頭,指定你希望客戶端、 代理和緩存響應(yīng)的中間件如何控制。
在Asp.Net Core 2.1 中,沒有了OutputCache,換成了ResponseCache,ResponseCache必須帶一個(gè)參數(shù):Duration 單位為秒,最少設(shè)置一秒鐘
然后再瀏覽器請(qǐng)求這個(gè)視圖
在瀏覽器的響應(yīng)頭的Cache-Control 中出現(xiàn)max-age=5, Http協(xié)議對(duì)此的解釋是
客戶端將不會(huì)接受其保留時(shí)間大于指定的秒數(shù)的響應(yīng)。 示例: max-age=60 (60 秒), max-age=2592000 (1 個(gè)月)
如果在瀏覽器中禁用緩存,那么ResponseCache不會(huì)有任何效果
Vary過濾
關(guān)于vary在Http響應(yīng)頭的作用就是:告訴緩存服務(wù)器或者CDN,我還是同一個(gè)瀏覽器的請(qǐng)求,你給我緩存就行了,如果你換個(gè)瀏覽器去請(qǐng)求,那么vary的值肯定為空,那么緩存服務(wù)器就會(huì)認(rèn)為你是一個(gè)新的請(qǐng)求,就會(huì)去讀取最新的數(shù)據(jù)給瀏覽器
參考資料:http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
在Http中 :no-store,請(qǐng)求和響應(yīng)的信息都不應(yīng)該被存儲(chǔ)在對(duì)方的磁盤系統(tǒng)中
ResponseCacheLocation.None是在Cache-Control設(shè)置一個(gè)no-cache屬性,讓瀏覽器不緩存當(dāng)前這個(gè)URL
緩存配置(CacheProfiles)
在一個(gè)正常的項(xiàng)目中,肯定有很多個(gè)控制器,但是不可能每個(gè)控制器的緩存策略都一樣,這時(shí)候,我們就需要一個(gè)緩存的配置來靈活應(yīng)對(duì)這個(gè)問題
在mvc的服務(wù)注入的時(shí)候,我們可以在option里面注入進(jìn)我們的緩存策略
然后我們?cè)谑褂玫臅r(shí)候,直接使用配置策略的名稱就好了
這樣我們就能和之前在特性后邊配置一樣了,這是視圖緩存,下面我們就來看看MemoryCache 是個(gè)什么東東
如果回到老版本的.NET,說到內(nèi)存緩存大家可能立馬想到了HttpRuntime.Cache,它位于System.Web命名空間下,但是在ASP.NET Core中System.Web已經(jīng)不復(fù)存在。今兒個(gè)就簡(jiǎn)單的聊聊如何在ASP.NET Core中使用內(nèi)存緩存
有幾個(gè)問題我們需要先進(jìn)行了解:
1.什么時(shí)候需要用到緩存?
一般將經(jīng)常訪問但是又不是經(jīng)常改變的數(shù)據(jù)放進(jìn)緩存是再好不過了,這樣可以明顯提高應(yīng)用程序的性能。
2.緩存的好處?
建議百度
不同于 ASP.NET Web 窗體和 ASP.NET MVC,ASP.NET Core 沒有內(nèi)置的 Cache 對(duì)象,可以拿來在控制器里面直接使用。 這里,內(nèi)存緩存時(shí)通過依賴注入來啟用的,因此第一步就是在 Startup 類中注冊(cè)內(nèi)存緩存的服務(wù)。如此,就得打開 Startup 類然后定位到 ConfigureServices() 方法,像下面這樣修改 ConfigureServices() 方法:
①首先需要在ConfigureServices中注冊(cè)緩存服務(wù)
services.AddMemoryCache()
為了向你的應(yīng)用程序加入內(nèi)存緩存能力,你需要在服務(wù)集合上調(diào)用 AddMemoryCache() 方法。采用這種辦法就可以讓一個(gè)內(nèi)存緩存(它是一個(gè) IMemoryCache 對(duì)象)的默認(rèn)實(shí)現(xiàn)可以被注入到控制器中去。
②在下面的代碼中從Home控制器的構(gòu)造函中獲取IMemoryCache實(shí)例(內(nèi)存緩存使用依賴注入來注入緩存對(duì)象)
如你所見,上述代碼聲明了一個(gè) ImemoryCache 的私有變量。該變量會(huì)被構(gòu)造器中被賦值。構(gòu)造器會(huì)通過 DI(依賴注入)接收到緩存參數(shù),然后被存儲(chǔ)在本地變量總,提供后續(xù)使用。
③關(guān)于緩存的使用常用的就是Set Get Remove,一般有以下幾種做法可以參考:
⑴可以使用 Set() 方法來在緩存中存東西
等你有了這個(gè) IMemoryCache 對(duì)象,就可以讀取或者向它寫入數(shù)據(jù)了。向緩存寫入數(shù)據(jù)項(xiàng)是相當(dāng)直接的
上述代碼在 Index() 這個(gè) action 中設(shè)置了一個(gè)緩存項(xiàng)。這是通過使用 IMemoryCache 的 Set<T>() 來完成的。Set() 方法的第一個(gè)參數(shù)是鍵名,用來標(biāo)識(shí)該數(shù)據(jù)項(xiàng)。第二個(gè)參數(shù)是鍵的取值。在此例中,我們存儲(chǔ)一個(gè)字符串的鍵和一個(gè)字符串的值,而你也可以存儲(chǔ)其它類型 (原生以及自定義的類型) 的鍵值對(duì)。
⑵可以使用 Get 方法來從緩存中獲取到一個(gè)數(shù)據(jù)項(xiàng)
等你向緩存中添加好了數(shù)據(jù),也許會(huì)想要在應(yīng)用程序的其它地方去獲取到該數(shù)據(jù),可以用 Get() 來做到。如下代碼會(huì)告訴你如何來做這件事情。
上述代碼從 HomeController 的另外一個(gè)action(Show)那里獲取到了一個(gè)緩存的數(shù)據(jù)項(xiàng)。Get() 方法會(huì)指定數(shù)據(jù)項(xiàng)的類型以及它的鍵名。如果該數(shù)據(jù)項(xiàng)存在的話,就會(huì)被返回并且被賦值給 timestamp 這個(gè)字符串變量。然后這個(gè) timestamp 的值就會(huì)被傳遞給 Show 視圖。
Show 視圖只是簡(jiǎn)單地輸出了 timestamp 的值,如下所示:
如果你觀察前面的示例,會(huì)發(fā)現(xiàn)每次你導(dǎo)航至 /Home/Index 的時(shí)候, 都會(huì)有一個(gè)新的 timestamp 被賦值給了緩存項(xiàng)。這是因?yàn)槲覀儾]有對(duì)此進(jìn)行檢查,規(guī)定只有在數(shù)據(jù)項(xiàng)不存在的時(shí)候才賦值。許多時(shí)候你都會(huì)想要這樣做的。這里有兩種辦法可以在 Index() 這個(gè) action 里面來做這樣的檢查。我們把兩種辦法都在下面列了出來
可以使用 TryGet() 來檢查緩存中是否存在特定的鍵值
第一種辦法使用了你早先用過的同一個(gè) Get() 方法,這一次它被拿來跟 if 塊一起用。如果 Get() 不能在緩存中找到指定的數(shù)據(jù)項(xiàng),IsNullOrEmpty() 就會(huì)返回 true。而只有這時(shí)候 Set() 才會(huì)被調(diào)用,一次來添加數(shù)據(jù)項(xiàng)。
第二種辦法更加優(yōu)雅一點(diǎn)。它使用 TryGet() 方法來獲取一個(gè)數(shù)據(jù)項(xiàng)。TryGet() 方法會(huì)返回一個(gè)布爾值來指明數(shù)據(jù)項(xiàng)有沒有被找到。實(shí)際的數(shù)據(jù)項(xiàng)可以使用一個(gè)輸出參數(shù)拉取出來。如果 TryGet() 返回false,Set() 就會(huì)被用來添加數(shù)據(jù)。
如果不存在的話,可以使用 GetOrCreate() 來添加一項(xiàng)
有時(shí)你需要從緩存中檢索現(xiàn)有項(xiàng)。如果該項(xiàng)目不存在,則希望添加該項(xiàng)。這兩個(gè)任務(wù) - 如果它存在獲取值,否則創(chuàng)建之 - 可以使用 GetOrCreate() 方法來實(shí)現(xiàn)。修改后的 Show() 方法展示了如何實(shí)現(xiàn)的
Show() 動(dòng)作現(xiàn)在使用 GetOrCreate() 方法。 GetOrCreate() 方法將檢查時(shí)間戳的鍵值是否存在。如果是,現(xiàn)有值將被賦值給局部變量。否則,將根據(jù)第二個(gè)參數(shù)中指定的邏輯創(chuàng)建一個(gè)新條目并將其添加到緩存中。
在緩存的數(shù)據(jù)項(xiàng)上面設(shè)置絕對(duì)和滾動(dòng)的過期時(shí)間
一個(gè)緩存項(xiàng)只要被添加到緩存就會(huì)一直存儲(chǔ),除非它被明確地使用 Remove() 從緩存中移除。你也可以在一個(gè)緩存項(xiàng)上面設(shè)置一個(gè)絕對(duì)和滾動(dòng)的過期時(shí)間。一個(gè)絕對(duì)的過期設(shè)置意味著該緩存項(xiàng)會(huì)在嚴(yán)格指定的日期和時(shí)間點(diǎn)被移除,而滾動(dòng)過期設(shè)置則意味著它在給定的一段時(shí)間量處于空閑狀態(tài)(也就是沒人去訪問)之后被移除。
為了能在一個(gè)緩存項(xiàng)上面設(shè)置這兩種過期策略,你要用到 MemoryCacheEntryOptions 對(duì)象。如下代碼向你展示了如何去使用。
上述代碼來自于修改過的 Index() action,它創(chuàng)建了一個(gè) MemoryCacheEntryOptions 的對(duì)象,然后將它的 AbsoluteExpiration 屬性設(shè)置為從此刻到一分鐘之后的一個(gè) DateTime 值,它還將 SlidingExpiration 屬性設(shè)置為一分鐘。這些值都指定了該緩存項(xiàng)會(huì)在一分鐘之后從緩存移除,不管其是否會(huì)被訪問。此外,如果該緩存項(xiàng)如初持續(xù)空閑了有一分鐘,它也會(huì)被從緩存中移除。
等你將 AbsoluteExpiration 和 SlidingExpiration 的值設(shè)置后, Set() 方法就可以被用來將一個(gè)數(shù)據(jù)項(xiàng)添加到緩存。這一次 MemoryCacheEntryOptions 對(duì)象會(huì)被作為第三個(gè)參數(shù)傳遞給 Set() 方法。
當(dāng)緩存項(xiàng)會(huì)被移除時(shí),可以連接回調(diào)
有時(shí)你會(huì)想要在緩存項(xiàng)從緩存中被移除時(shí)收到通知。可能會(huì)有多種原因需要從緩存中移除數(shù)據(jù)項(xiàng)。例如,因?yàn)槊鞔_地執(zhí)行了 Remove() 方法而移除了一個(gè)緩存項(xiàng), 也有可能是因?yàn)樗?AbsoluteExpiration 和 SlidingExpiration 值已經(jīng)到期而被移除,諸如此類的原因。
為了能知道項(xiàng)目是何時(shí)從緩存移除的,你需要編寫一個(gè)緩存函數(shù)。如下代碼向你展示了如何去做這件事情
請(qǐng)仔細(xì)觀察這段代碼。 MyCallback() 是 HomeController 類里面的一個(gè)私有靜態(tài)函數(shù),它有四個(gè)參數(shù)。前面兩個(gè)參數(shù)表示剛剛刪除的緩存項(xiàng)的鍵和值,第三個(gè)參數(shù)表示的是該數(shù)據(jù)項(xiàng)被刪除的原因。EvictionReason 是一個(gè)枚舉類型,它維護(hù)者各種可能的刪除原因,如過期,刪除以及替換。
在回調(diào)函數(shù)的內(nèi)部,我們會(huì)基于刪除的原因構(gòu)造一個(gè)字符串消息。我們想要將此消息設(shè)置成另外一個(gè)緩存項(xiàng)。這樣做的話就需要訪問 HomeController 的緩存對(duì)象,此時(shí)狀態(tài)參數(shù)就可以排上用場(chǎng)了。使用狀態(tài)對(duì)象,你可以對(duì) HomeController 的緩存對(duì)象進(jìn)行控制,并使用 Set() 增加一個(gè) callbackMessage 緩存項(xiàng)。
你可以通過 Show() 這個(gè) action 來訪問到 callbackMessage,如下所示:
最后就可以在 Show 視圖中顯示出來了:
一些建議,像上面提到的設(shè)置緩存數(shù)據(jù)項(xiàng)的過期時(shí)間那塊,如果一個(gè)項(xiàng)目中所有的緩存過期時(shí)間是一致的,我們可以有更簡(jiǎn)單的做法,而不是每個(gè)地方都去寫一堆這個(gè):
可以在頭部定義一個(gè)共有的
Cache是自定義的一個(gè)緩存類,其中GetMemoryCacheEntryOptions就是獲取當(dāng)前緩存設(shè)置項(xiàng)的,代碼如下:
這里面我們將過期時(shí)間放到配置文件中。
這樣,我們的寫法就可以簡(jiǎn)寫很多,當(dāng)然,剛才提到了是使用的 IMemoryCache 的 Set<T>() 來完成的,所以,這里我們不僅可以傳String,還可以按需傳遞,比如:
到這里,你已經(jīng)大概知道了MemoryCache 的簡(jiǎn)單使用方式,剩下的就自行研究吧~
出處:https://www.cnblogs.com/zhangxiaoyong/p/9472637.html 作者:瀟十一郎
nderer
這貌似是360瀏覽器專用,兼容360的利器啊,,360默認(rèn)是用IE7去渲染頁面的,不管你的系統(tǒng)裝了多高版本的IE,這種行為真是業(yè)界毒瘤啊。
"renderer" content="webkit">//默認(rèn)webkit內(nèi)核
"renderer" content="ie-comp">//默認(rèn)IE兼容模式
"renderer" content="ie-stand">//默認(rèn)IE標(biāo)準(zhǔn)模式
Expires (期限)
說明:指定網(wǎng)頁在緩存中的過期時(shí)間,一旦網(wǎng)頁過期,必須到服務(wù)器上重新調(diào)閱。
用法:
注意:必須使用GMT的時(shí)間格式,或直接設(shè)為0(數(shù)字表示多少時(shí)間后過期)。
Pragma (cach模式)
說明:禁止瀏覽器從本地機(jī)的緩存中調(diào)閱頁面內(nèi)容。
用法:
注意:網(wǎng)頁不保存在緩存中,每次訪問都刷新頁面。這樣設(shè)定,訪問者將無法脫機(jī)瀏覽。
Set-Cookie (cookie設(shè)定)
說明:瀏覽器訪問某個(gè)頁面時(shí)會(huì)將它存在緩存中,下次再次訪問時(shí)就可從緩存中讀取,以提高速度。
當(dāng)你希望訪問者每次都刷新你廣告的圖標(biāo),或每次都刷新你的計(jì)數(shù)器,就要禁用緩存了。
通常HTML文件沒有必要禁用緩存,對(duì)于ASP等頁面,就可以使用禁用緩存,因?yàn)槊看慰吹降捻撁娑际窃诜?wù)器動(dòng)態(tài)生成的,緩存就失去意義。如果網(wǎng)頁過期,那么存盤的cookie將被刪除。
Window-target (顯示窗口的設(shè)定)
說明:強(qiáng)制頁面在當(dāng)前窗口以獨(dú)立頁面顯示。
用法:
注意:這個(gè)屬性是用來防止別人在框架里調(diào)用你的頁面。Content選項(xiàng):_blank、_top、_self、_parent
Pics-label (網(wǎng)頁RSAC等級(jí)評(píng)定)
說明:在IE的Internet選項(xiàng)中有一項(xiàng)內(nèi)容設(shè)置,可以防止瀏覽一些受限制的網(wǎng)站,而網(wǎng)站的限制級(jí)
別就是通過該參數(shù)來設(shè)置的。
用法:I gen comment ‘RSACi North America Sever’ by
for ‘http://www.microsoft.com’ on ‘1997.06.30T14:21-0500′ r(n0 s0 v0 l0))">
注意:不要將級(jí)別設(shè)置的太高。RSAC的評(píng)估系統(tǒng)提供了一種用來評(píng)價(jià)Web站點(diǎn)內(nèi)容的標(biāo)準(zhǔn)。
用戶可以設(shè)置Microsoft Internet Explorer(IE3.0以上)來排除包含有色情和暴力內(nèi)容的站點(diǎn)。
上面這個(gè)例子中的HTML取自Microsoft的主頁。代碼中的(n 0 s 0 v 0 l 0)表示該站點(diǎn)不包含不健康內(nèi)容。
級(jí)別的評(píng)定是由RSAC,即美國(guó)娛樂委員會(huì)的評(píng)級(jí)機(jī)構(gòu)評(píng)定的,如果你想進(jìn)一步了解RSAC評(píng)估系統(tǒng)的等級(jí)內(nèi)容,或者你需要評(píng)價(jià)自己的網(wǎng)站,可以訪問RSAC的站點(diǎn):http://www.rsac.org/。
Content-Script-Type (腳本相關(guān))
說明:這是近來W3C的規(guī)范,指明頁面中腳本的類型。
RSS 網(wǎng)站地圖-Sitemap
復(fù)制代碼保存到一個(gè)sitemap.xml(或者ror.xml)文件中,然后上傳到你應(yīng)用的根目錄下。
并且把下面代碼增加到你站點(diǎn)主頁的 標(biāo)簽中,主要是為了方便搜索引擎來讀取。
如果你的站點(diǎn)地圖文件名是ror.xml,記得要把代碼中的href改成href="ror.xml"
Content-Type和Content-Language (顯示字符集的設(shè)定)
說明:設(shè)定頁面使用的字符集,用以說明主頁制作所使用的文字已經(jīng)語言,
瀏覽器會(huì)根據(jù)此來調(diào)用相應(yīng)的字符集顯示page內(nèi)容。
注意:
該meta標(biāo)簽定義了HTML頁面所使用的字符集為GB2132,就是國(guó)標(biāo)漢字碼。
如果將其中的“charset=GB2312"替換成“BIG5",則該頁面所用的字符集就是繁體中文Big5碼。
當(dāng)你瀏覽一些國(guó)外的站點(diǎn)時(shí),IE瀏覽器會(huì)提示你要正確顯示該頁面需要下載xx語支持。
這個(gè)功能就是通過讀取HTML頁面meta標(biāo)簽的Content-Type屬性而得知需要使用哪種字符集顯示該頁面的。
如果系統(tǒng)里沒有裝相應(yīng)的字符集,則IE就提示下載。
其他的語言也對(duì)應(yīng)不同的charset,比如日文的字符集是“iso-2022-jp ",韓文的是“ks_c_5601"。
Content-Type的Content還可以是:text/xml等文檔類型;
Charset選項(xiàng):
ISO-8859-1(英文)、BIG5、UTF-8、SHIFT-Jis、Euc、Koi8-2、us-ascii,
x-mac-roman, iso-8859-2, x-mac-ce, iso-2022-jp, x-sjis, x-euc-jp,euc-kr,
iso-2022-kr, gb2312, gb_2312-80, x-euc-tw, x-cns11643-1,x-cns11643-2等字符集;
Content-Language的Content還可以是:EN、FR等語言代碼。
webapp里主要的mate用途
添加到主屏幕后,全屏顯示。
這meta的作用就是刪除默認(rèn)的蘋果工具欄和菜單欄。content有兩個(gè)值”yes”和”no”,當(dāng)我們需要顯示工具欄和菜單欄時(shí),這個(gè)行meta就不用加了,默認(rèn)就是顯示。
默認(rèn)值為default(白色),可以定為black(黑色)和black-translucent(灰色半透明)。
注意: 若值為“black-translucent”將會(huì)占據(jù)頁面px位置,浮在頁面上方(會(huì)覆蓋頁面20px高度–iphone4和itouch4的Retina屏幕為40px)。
在iOS中有兩個(gè)meta值,apple-mobile-web-app-capable和apple-mobile-web-app-status-bar-style,這兩個(gè)會(huì)讓網(wǎng)頁內(nèi)容以應(yīng)用程序風(fēng)格顯示,并使?fàn)顟B(tài)欄透明。
說明: 這個(gè)link就是設(shè)置web app的放置主屏幕上icon文件路徑。
圖片尺寸可以設(shè)定為57*57(px)或者Retina可以定為114*114(px),ipad尺寸為72*72(px)
apple-touch-icon
iOS用rel="apple-touch-icon",android 用rel="apple-touch-icon-precomposed"。這樣就能在用戶把網(wǎng)頁存為書簽時(shí),在手機(jī)HOME界面創(chuàng)建應(yīng)用程序樣式的圖標(biāo)。
name="sharecontent" data-msg-img="縮略圖地址" data-msg-title="標(biāo)題" data-msg-content="簡(jiǎn)介" data-msg-callBack="" data-line-img="縮略圖地址" data-line-title="標(biāo)題" data-line-callBack=""/>
ps:
告訴瀏覽器以什么版本的IE的兼容模式來顯示網(wǎng)頁
其中最后一行是永遠(yuǎn)以最新的IE版本模式來顯示網(wǎng)頁的。
另外加上Emulate模式
Emulate模式后則更重視
(細(xì)心的人會(huì)注意到,用IE9去訪問帶有x-ua-compatible的頁面時(shí)是不會(huì)出現(xiàn)兼容視圖按鈕的)
防止所有搜索引擎將網(wǎng)站中的網(wǎng)頁編入索引
<meta name="robots" content="noindex">
們知道,在使用瀏覽器的后退和前進(jìn)按鈕時(shí),瀏覽器會(huì)使用緩存來優(yōu)化您的頁面加載過程。它顯著改善了用戶的瀏覽體驗(yàn)——尤其是那些網(wǎng)絡(luò)或設(shè)備較慢的用戶。作為 Web 開發(fā)人員,了解如何在所有瀏覽器中針對(duì)這種緩存優(yōu)化頁面至關(guān)重要,這樣您的用戶才能獲得收益。
回退前進(jìn)緩存是一種內(nèi)存緩存,用于在用戶導(dǎo)航離開時(shí)存儲(chǔ)頁面(包括 JavaScript 堆)的完整快照。 整個(gè)頁面都在內(nèi)存中,如果用戶決定返回,瀏覽器可以快速輕松地恢復(fù)它。比如當(dāng)點(diǎn)擊返回時(shí),在那一刻,該緩存可以對(duì)上一個(gè)頁面的加載速度產(chǎn)生很大的影響:
下面是有緩存和沒緩存的加載回退頁面的過程:
回退前進(jìn)緩存是如何工作的
回退前進(jìn)緩存使用的“緩存”不同于 HTTP 緩存(它對(duì)于加快重復(fù)導(dǎo)航也很有用)。 回退前進(jìn)緩存是在內(nèi)存緩存中整個(gè)頁面的快照(包括 JavaScript 堆),而 HTTP 緩存僅包含對(duì)先前發(fā)出的請(qǐng)求的響應(yīng)。由于加載頁面所需的所有請(qǐng)求都可以從 HTTP 緩存中完成是非常罕見的,因此使用回退前進(jìn)緩存恢復(fù)的重復(fù)訪問總是比優(yōu)化得最好的非回退前進(jìn)緩存導(dǎo)航更快。
然而,在內(nèi)存中創(chuàng)建頁面快照涉及到如何最好地保存正在進(jìn)行的代碼方面的一些復(fù)雜性。例如,當(dāng)頁面在回退前進(jìn)緩存中時(shí),如何處理超時(shí)的 setTimeout() 調(diào)用?
答案是瀏覽器暫停運(yùn)行任何掛起的計(jì)時(shí)器或未解決的Promise——就是說會(huì)掛起所有任務(wù)隊(duì)列中的任務(wù)——并在當(dāng)從回退前進(jìn)緩存恢復(fù)頁面時(shí)恢復(fù)處理任務(wù)。
在某些情況下,這是相當(dāng)?shù)偷娘L(fēng)險(xiǎn)(例如,setTimeout或Promise),但在其他情況下,它可能會(huì)導(dǎo)致非常混亂或意外的行為。例如,如果瀏覽器暫停了作為 IndexedDB 事務(wù)的一部分所需的任務(wù),它可能會(huì)影響同一源中的其他打開的選項(xiàng)卡(因?yàn)槎鄠€(gè)選項(xiàng)卡可以同時(shí)訪問相同的 IndexedDB 數(shù)據(jù)庫)。因此,瀏覽器通常不會(huì)嘗試在 IndexedDB 事務(wù)的中間緩存頁面或使用可能影響其他頁面的 API。
可以觀察回退前進(jìn)緩存的API
雖然回退前進(jìn)緩存是瀏覽器自動(dòng)進(jìn)行的優(yōu)化,但對(duì)于開發(fā)人員來說,知道它何時(shí)發(fā)生仍然很重要,這樣他們就可以優(yōu)化他們的頁面并相應(yīng)地調(diào)整任何指標(biāo)或性能測(cè)量。
用于觀察回退前進(jìn)緩存的主要事件是頁面轉(zhuǎn)換事件——pageshow 和 pagehide——它們?cè)?strong>回退前進(jìn)緩存存在的時(shí)候就已經(jīng)存在,并且在當(dāng)今使用的幾乎所有瀏覽器中都得到了支持。較新的頁面生命周期事件(freeze和resume)也會(huì)在頁面進(jìn)出回退前進(jìn)緩存時(shí)以及在某些其他情況下調(diào)度。
觀察何時(shí)從回退前進(jìn)緩存恢復(fù)頁面:
pageshow 事件在頁面初始加載時(shí)以及頁面從緩存恢復(fù)時(shí)的 load 事件之后立即觸發(fā)。 pageshow 事件有一個(gè)persisted屬性,如果頁面從緩存恢復(fù),則該屬性為 true(如果不是,則為 false)。 您可以使用持久化屬性來區(qū)分常規(guī)頁面加載和緩存恢復(fù)。 例如:
觀察頁面什么時(shí)候進(jìn)入回退前進(jìn)緩存
pagehide 是 pageshow 事件的對(duì)應(yīng)事件。 pageshow 事件在頁面正常加載或從緩存恢復(fù)時(shí)觸發(fā)。 pagehide 事件在頁面正常卸載或?yàn)g覽器嘗試將其放入緩存時(shí)觸發(fā)。
pagehide 事件也有一個(gè)persisted屬性,如果它是假的,那么你可以確信頁面不會(huì)進(jìn)入回退前進(jìn)緩存。 但是,如果persisted 屬性為真,則不能保證頁面會(huì)被緩存。 這意味著瀏覽器打算緩存該頁面,但可能存在無法緩存的因素。下面會(huì)解釋幾種原因,導(dǎo)致它可能仍然不能進(jìn)入緩存并被丟棄。
為回退前進(jìn)緩存優(yōu)化你的頁面
并非所有頁面都存儲(chǔ)在回退前進(jìn)緩存中,即使頁面確實(shí)存儲(chǔ)在那里,它也不會(huì)無限期地留在那里。 開發(fā)人員必須了解是什么使頁面符合(和不符合)使用緩存的條件,以最大限度地提高其緩存命中率。以下部分概述了使瀏覽器盡可能緩存您的頁面的最佳實(shí)踐。
不要使用 unload 事件
在所有瀏覽器中優(yōu)化回退前進(jìn)緩存的最重要方法是永遠(yuǎn)不要使用 unload 事件。
unload 事件對(duì)瀏覽器來說是有問題的,在 unload 事件觸發(fā)后頁面將不會(huì)繼續(xù)存在。這提出了一個(gè)挑戰(zhàn),因?yàn)槠渲性S多頁面也是在假設(shè)用戶導(dǎo)航離開時(shí)會(huì)觸發(fā) unload 事件的假設(shè)下構(gòu)建的,這不再是真的(并且很長(zhǎng)一段時(shí)間都不是真的)。所以瀏覽器面臨兩難境地,他們必須在可以改善用戶體驗(yàn)的東西之間做出選擇——但也可能會(huì)冒著破壞頁面的風(fēng)險(xiǎn)。
如果 Chrome 和 Firefox 添加了卸載偵聽器,則選擇使頁面不符合回退前進(jìn)緩存的條件,這樣風(fēng)險(xiǎn)較小,但也會(huì)取消許多頁面被緩存的資格。 Safari 將嘗試使用 unload 事件偵聽器緩存某些頁面,但為了減少潛在的損壞,它不會(huì)在用戶導(dǎo)航離開時(shí)運(yùn)行 unload 事件,這使得該事件非常不可靠。
不要使用 unload 事件,而是使用 pagehide 事件。 pagehide 事件在當(dāng)前觸發(fā) unload 事件的所有情況下觸發(fā),并且當(dāng)頁面放入回退前進(jìn)緩存時(shí)也會(huì)觸發(fā)。
事實(shí)上,Lighthouse v6.2.0 添加了一個(gè) no-unload-listeners 審計(jì),如果他們的頁面上的任何 JavaScript(包括來自第三方庫的 JavaScript)添加了 unload 事件監(jiān)聽器,它將警告開發(fā)人員。
正確的做法:
避免 window.opener 引用
在某些瀏覽器(包括基于 Chromium 的瀏覽器)中,如果頁面是使用 window.open() 或(在 88 版之前基于 Chromium 的瀏覽器中)從帶有 target=_blank 的鏈接打開的——沒有指定 rel="noopener"——那么 打開頁面將引用打開頁面的窗口對(duì)象。
除了存在安全風(fēng)險(xiǎn)之外,具有非空 window.opener 引用的頁面不能安全地放入緩存,因?yàn)檫@可能會(huì)破壞任何試圖訪問它的頁面。
因此,最好盡可能避免使用 rel="noopener" 創(chuàng)建 window.opener 引用。 如果您的站點(diǎn)需要打開一個(gè)窗口并通過 window.postMessage() 或直接引用 window 對(duì)象來控制它,則打開的窗口和打開器都沒有資格使用緩存。
始終在用戶導(dǎo)航離開之前關(guān)閉打開的連接
如上所述,當(dāng)頁面被放入緩存時(shí),所有計(jì)劃的 JavaScript 任務(wù)都會(huì)暫停,然后在頁面從緩存中取出時(shí)恢復(fù)。如果這些計(jì)劃好的 JavaScript 任務(wù)僅訪問 DOM API(或僅與當(dāng)前頁面隔離的其他 API),那么在頁面對(duì)用戶不可見時(shí)暫停這些任務(wù)不會(huì)導(dǎo)致任何問題。
但是,如果這些任務(wù)連接到的 API 也可以從同一來源的其他頁面訪問(例如:IndexedDB、Web Locks、WebSockets 等),這可能會(huì)出現(xiàn)問題,因?yàn)闀和_@些任務(wù)可能會(huì)阻止其他選項(xiàng)卡中的代碼運(yùn)行.
因此,某些瀏覽器在以下情況下不會(huì)嘗試將頁面放入緩存:
如果您的頁面使用這些 API 中的任何一個(gè),最好在 pagehide 或 freeze 事件期間始終關(guān)閉連接并刪除或斷開觀察者。這將允許瀏覽器安全地緩存頁面,而不會(huì)影響其他打開的選項(xiàng)卡。然后,如果頁面從緩存恢復(fù),您可以重新打開或重新連接到這些 API(在 pageshow 或 resume 事件中)。
以下示例顯示了如何在使用 IndexedDB 時(shí)通過關(guān)閉 pagehide 事件偵聽器中的打開連接來確保您的頁面符合緩存條件:
緩存恢復(fù)后更新陳舊或敏感數(shù)據(jù)
如果您的站點(diǎn)保留用戶狀態(tài)(尤其是任何敏感的用戶信息),則需要在從回退前進(jìn)緩存恢復(fù)頁面后更新或清除該數(shù)據(jù)。例如,如果用戶導(dǎo)航到結(jié)帳頁面然后更新他們的購物車,如果從緩存恢復(fù)過時(shí)的頁面,則返回導(dǎo)航可能會(huì)顯示過時(shí)的信息。
另一個(gè)更關(guān)鍵的示例是,如果用戶在公共計(jì)算機(jī)上退出站點(diǎn),并且下一個(gè)用戶單擊后退按鈕。 這可能會(huì)暴露用戶在注銷時(shí)認(rèn)為已清除的私人數(shù)據(jù)。為避免此類情況,如果 event.persisted 為 true,則最好在 pageshow 事件之后始終更新頁面。
以下代碼檢查 pageshow 事件中是否存在特定于站點(diǎn)的 cookie,如果未找到 cookie,則重新加載:
測(cè)試一下保證你的頁面會(huì)被緩存
Chrome DevTools 可以幫助您測(cè)試您的頁面,以確保它們針對(duì)回退前進(jìn)緩存進(jìn)行了優(yōu)化,并確定可能阻止它們符合條件的任何問題。
要測(cè)試特定頁面,請(qǐng)?jiān)?Chrome 中導(dǎo)航到該頁面,然后在 DevTools 中轉(zhuǎn)到 Application > Back-forward Cache。 接下來單擊 Run Test 按鈕,DevTools 將嘗試導(dǎo)航并返回以確定頁面是否可以從回退前進(jìn)緩存恢復(fù)。
如果成功,則會(huì)顯示從緩存恢復(fù)成功,失敗也有提示,并告訴你原因。
成功
比如百度使用了unload導(dǎo)致緩存失敗 :)
結(jié)語:
回退前進(jìn)緩存對(duì)提高性能,及用戶體驗(yàn)很有幫助。大家要寫正確的代碼來使自己的頁面盡量被緩存,這樣你們的網(wǎng)站才能大大獲益。
*請(qǐng)認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。