PWA(Progressive Web App)入门系列:Cache Storage Cache
前言
目前瀏覽器的存儲機(jī)制有很多,如:indexedDB、localStorage、sessionStorage、File System API、applicationCache 等等,那為什么又制定了一套 Cache API 呢?對比其他存儲機(jī)制有什么優(yōu)勢?
簡介
Cache API 是一套搭配 PWA serviceworker 賦能的存儲機(jī)制,來實(shí)現(xiàn)請求數(shù)據(jù)離線功能。與 applicationCache 相似,提供了力度極細(xì)的存儲控制能力,內(nèi)容完全由腳本控制。常在 serviceworker 中搭配 Fetch 使用,且同一個 URL 不同 header 可以存儲多個 Response。不提供跨域共享,且與HTTP緩存完全隔離。
與其他存儲機(jī)制的區(qū)別:
- Cache API 是異步化的存儲方式,serviceworker中必須使用異步化存儲。
- Cache API 是以 Requst 做為 key,Response 做為 value 進(jìn)行存儲的,異步化的 IndexDB 基于結(jié)構(gòu)化克隆存儲, 無法存儲流式數(shù)據(jù),轉(zhuǎn)換成本過高,增大內(nèi)存使用及影響速度。
CacheStorage 方法
CacheStorage 是 Cache 對象存儲的接口,可以通過兩種方式獲取:
ServiceWorkerGlobalScope.cachesWindow.caches注: 必須在 https 環(huán)境下才能使用。
下面都是在 ServiceWorkerGlobalScope 環(huán)境下。
open
語法:
// cachs 是 CacheStorage 實(shí)例的只讀全局變量 caches.open(cacheName).then(cache => {// 處理打開的 cache 實(shí)例相關(guān)操作 });打開(如果沒有 cacheName,則創(chuàng)建)為 cacheName 的 Cache 實(shí)例。
返回 Promise,resolve 為Cache 實(shí)例。
delete
語法:
caches.delete(cacheName).then(boolean => {// true: cache 發(fā)現(xiàn)并已經(jīng)刪除 });查找匹配 cacheName 的 Cache 對象。找到則刪除 Cache 對象并返回一個 resolve 為 true 的 Promise;沒找到 Cache 對象,則返回 false。
keys
語法:
caches.keys().then(keyList => {//對 keyList 做操作 });返回 Promise。包含 CacheStorage 下所有的 Cache 對象名稱字符串的數(shù)組。
has
語法:
caches.has(cacheName).then(boolean => {// true: cacheName 緩存存在 });返回一個 Promise 對象,緩存存在時 resolve 的布爾值為 true 否則為 false。
match
語法:
caches.match(request[, options]).then(response => {// response 操作// 如果未匹配到,則 resolve 返回 undefined });參數(shù):
request: 要匹配的 Request。可以是 Request 對象或 URL 字符串。
options:(可選) 可選。用于控制如何進(jìn)行匹配操作。
- ignoreSearch:Boolean,false。匹配時,是否忽略 url 的查詢參數(shù)。
- ignoreMethod:Boolean,false。true 時忽略請求方法(GET/HEAD)匹配。
- ignoreVary:Boolean,false。true 時忽略 Vary 頭匹配。(什么是Vary)
- cacheName:String。表示所要搜索的緩存名稱。如果不設(shè)置則全局搜索,查找到第一個,立即返回。
Cache 方法
Cache 是 CacheStorage 的存儲實(shí)現(xiàn),以 Request 做為 key,以 Response 做為 value 來進(jìn)行存儲。可以通過 CacheStorage.open(cacheName) 打開 Cache 來進(jìn)行操作。
Cache 數(shù)據(jù)生成后,將會一直存在,修改/刪除 需要通過腳本自己去實(shí)現(xiàn)。
注: Cache.add/Cache.put/Cache.addAll 只能在 request method 為 GET 的情況下使用。并且相同的 request key 下的 cache,在這三個方法下會被覆蓋。
put
通過指定的 request 和 response 添加到 cache 中。
response 的 status 可以是任意類型。
語法:
cache.put(request, response).then(() => {// 將 request/response 鍵值對添加到cache中 });參數(shù):
- request:你想添加的 Request 。
- response:你想添加匹配 Request 的 Response。
注: request 參數(shù),method 只支持 GET,否則會出現(xiàn)「TypeError: Request method POST is unsupported」 錯誤。
delete
刪除匹配 request key 的 cache ,找到并刪除成功 resolve(true)。
語法:
cache.delete(request,{options}).then(boolean => {// true: 你的 cache 已經(jīng)刪除 });參數(shù):
request: 請求刪除的 Request。
options:(可選) 控制刪除搜索 key 如何去匹配(同 match 方法)。
- ignoreSearch:Boolean,false。匹配時,是否忽略 url 的查詢參數(shù)。
- ignoreMethod:Boolean,false。true 時忽略請求方法(GET/HEAD)匹配。
- ignoreVary:Boolean,false。true 時忽略 Vary 頭匹配。(什么是Vary)
add
給定 request 參數(shù),自動請求獲取 response,并填入 cache 對象中。
等于 fetch + cache.put 。
注: response status 為 opaque 的不能通過 add 方法添加,返回 reject。
語法:
cache.add(request).then(() => {// request 已經(jīng)添加到 cache });addAll
和 Cache.add 作用相同,參數(shù)為 request 的數(shù)組。
注: 只有在所有 requests 都成功的情況下,才能完成 cache 緩存。
語法:
cache.addAll(requests[]).then(() => {// 所有 requests 都添加到 cache 。 });match
返回匹配 request key 的第一個 cache。
注: 即使沒有匹配到,也將返回 resolve,只是值為 undefined。
語法:
cache.match(request, {options}).then(response => {// 對 response 做一些處理 });參數(shù):
request: 請求匹配的 Request。
options:(可選) 控制搜索 key 如何去匹配(同 match 方法)。
- ignoreSearch:Boolean,false。匹配時,是否忽略 url 的查詢參數(shù)。
- ignoreMethod:Boolean,false。true 時忽略請求方法(GET/HEAD)匹配。
- ignoreVary:Boolean,false。true 時忽略 Vary 頭匹配。(什么是Vary)
matchAll
作用同 Cache.match,區(qū)別在于 Cache.match 返回匹配的 responses[0],而 Cache.matchAll 返回所有匹配的 responses 數(shù)組。
語法:
cache.matchAll(request,{options}).then(responses => {// 對 responses 數(shù)組做一些處理 });參數(shù):
request: 請求匹配的 Request。
options:(可選) 控制搜索 key 如何去匹配(同 match 方法)。
- ignoreSearch:Boolean,false。匹配時,是否忽略 url 的查詢參數(shù)。
- ignoreMethod:Boolean,false。true 時忽略請求方法(GET/HEAD)匹配。
- ignoreVary:Boolean,false。true 時忽略 Vary 頭匹配。(什么是Vary)
keys
返回當(dāng)前 cache 實(shí)例下所有的 key。
注: 具有相同URL但不同請求頭的請求,如果它們的響應(yīng)頭中有 VARY 頭部,則他們可以被返回。
語法:
cache.keys(request,{options}).then(keys => {// 對 requests 做一些處理 });參數(shù):
request:(可選) 如果一個相關(guān) Request key 被指定,則返回對應(yīng)的 Request。
options:(可選) 控制搜索 key 如何去匹配(同 match 方法)。
- ignoreSearch:Boolean,false。匹配時,是否忽略 url 的查詢參數(shù)。
- ignoreMethod:Boolean,false。true 時忽略請求方法(GET/HEAD)匹配。
- ignoreVary:Boolean,false。true 時忽略 Vary 頭匹配。(什么是Vary)
調(diào)試查看
可以通過 Chrome 的 DevTools進(jìn)行查看。
Application → Cache → Cache Storage
Cache Storage 中是以 caches.open 創(chuàng)建的 cacheName 的 cache,右側(cè)列表中是通過 put/add/addAll 添加的 request key,點(diǎn)擊可以在下方查看相關(guān)的 request 和 response。
緩存空間問題
web 端的離線存儲方式有三種,分別是:
- Temporary
- Persistent
- Unlimited
而 Cache 屬于 Temporary 類型。Temporary 存儲是一種臨時存儲,任何Web應(yīng)用程序都可以在沒有前期配額請求或用戶提示的情況下使用,但存儲的數(shù)據(jù)可以被瀏覽器隨時刪掉(占用空間過多時,自動清理)。可以類比于文件系統(tǒng)的 / tmp 目錄。
在 Chrome 和 Opera 中可以使用新的實(shí)驗(yàn)性 API 向設(shè)備請求持久化存取權(quán)限:
navigator.storage.persist().then(isGranted => {// true : 授權(quán) })各瀏覽器的離線空間:
- Chrome <6% of free space
- Firefox <10% of free space
- Safari <50MB
- IE10 <250MB
- Edge Depenent on volume size
溢出處理策略:
- Chrome LRU once Chrome runs out of sapce
- Firefox LRU if the whole disk gets full
- Safari No eviction
- Edge No eviction
實(shí)際數(shù)據(jù)可通過 Quota Management API 來查看。
常見問題
跨域緩存
對于跨域緩存,跨域的資源需要開啟 Access-Control-Allow-Origin 頭部,并且 Request 的 mode 需要設(shè)置為 cors。
const req = new Request("https://cross.com", { mode: "cors" });fetch(req).then(response => {caches.open("cacheName").then(cache => {cache.put(req, res);}); });如果跨域資源沒有開啟 Access-Control-Allow-Origin 頭部,則需要把 mode 設(shè)置為 no-cors,但會導(dǎo)致 response 的 status 為 0 的 opaque 響應(yīng),后面會講。
POST 緩存
因 Cache 中的規(guī)范指出只能存儲 GET 類型的 Request,所以想緩存 POST 類型的 Request 怎么辦呢?
這里建議兩種方式:
opaque 不透明響應(yīng)緩存
針對 response 的 status 為 0 的 opaque 響應(yīng)資源,也是可以存儲到 cache 中的,但是并不建議存儲。因?yàn)轫憫?yīng)狀態(tài)是 0,并不能確認(rèn)資源是否完整及正確,緩存下來后,在 cache 中也是無法查看其長度大小的,并且會導(dǎo)致一些存儲問題。
并且,突然間 Cache Storage 變成了 10.3MB。
但存儲的這個 opaque 狀態(tài)的響應(yīng)實(shí)際只有幾 kb,但緩存起來卻達(dá)到好幾 MB 這是什么原因呢?
其實(shí)這是 Chrome 瀏覽器層為防止出現(xiàn)安全問題,所以把所有 opaque 狀態(tài)的請求都以這種幾 MB 的方式進(jìn)行填充來保證安全的。
所以針對 opaque 狀態(tài)的請求,建議:
- 不進(jìn)行 opaque 狀態(tài)類型的緩存。
- 對 opaque 狀態(tài)類弄的緩存添加 Access-Control-Allow-Origin 頭來實(shí)現(xiàn)狀態(tài)透明。
瀏覽器兼容性
博客名稱:王樂平博客
CSDN博客地址:http://blog.csdn.net/lecepin
本作品采用知識共享署名-非商業(yè)性使用-禁止演繹 4.0 國際許可協(xié)議進(jìn)行許可。總結(jié)
以上是生活随笔為你收集整理的PWA(Progressive Web App)入门系列:Cache Storage Cache的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2015 Spark 将走向哪里?
- 下一篇: webpack+vue实现项目