PWA(Progressive Web App)入門系列:Cache Storage & Cache

前言

目前瀏覽器的存儲機制有不少,如:indexedDB、localStorage、sessionStorage、File System API、applicationCache 等等,那爲何又制定了一套 Cache API 呢?對比其餘存儲機制有什麼優點?web

簡介

Cache API 是一套搭配 PWA serviceworker 賦能的存儲機制,來實現請求數據離線功能。與 applicationCache 類似,提供了力度極細的存儲控制能力,內容徹底由腳本控制。常在 serviceworker 中搭配 Fetch 使用,且同一個 URL 不一樣 header 能夠存儲多個 Response。不提供跨域共享,且與HTTP緩存徹底隔離。api

與其餘存儲機制的區別:跨域

  • Cache API 是異步化的存儲方式,serviceworker中必須使用異步化存儲。
  • Cache API 是以 Requst 作爲 key,Response 作爲 value 進行存儲的,異步化的 IndexDB 基於結構化克隆存儲, 沒法存儲流式數據,轉換成本太高,增大內存使用及影響速度。

CacheStorage 方法

CacheStorage 是 Cache 對象存儲的接口,能夠經過兩種方式獲取:數組

ServiceWorkerGlobalScope.caches

Window.caches
複製代碼

注: 必須在 https 環境下才能使用。瀏覽器

下面都是在 ServiceWorkerGlobalScope 環境下。緩存

open

語法:安全

// cachs 是 CacheStorage 實例的只讀全局變量
caches.open(cacheName).then(cache => {
  // 處理打開的 cache 實例相關操做
});
複製代碼

打開(若是沒有 cacheName,則建立)爲 cacheName 的 Cache 實例。session

返回 Promise,resolve 爲Cache 實例。app

delete

語法:cors

caches.delete(cacheName).then(boolean => {
  // true: cache 發現並已經刪除
});
複製代碼

查找匹配 cacheName 的 Cache 對象。找到則刪除 Cache 對象並返回一個 resolve 爲 true 的 Promise;沒找到 Cache 對象,則返回 false。

keys

語法:

caches.keys().then(keyList => {
  //對 keyList 作操做
});
複製代碼

返回 Promise。包含 CacheStorage 下全部的 Cache 對象名稱字符串的數組。

has

語法:

caches.has(cacheName).then(boolean => {
  // true: cacheName 緩存存在
});
複製代碼

返回一個 Promise 對象,緩存存在時 resolve 的布爾值爲 true 不然爲 false。

match

語法:

caches.match(request[, options]).then(response => {
  // response 操做
  // 若是未匹配到,則 resolve 返回 undefined
});
複製代碼

參數:

request: 要匹配的 Request。能夠是 Request 對象或 URL 字符串。

options:(可選) 可選。用於控制如何進行匹配操做。

  • ignoreSearch:Boolean,false。匹配時,是否忽略 url 的查詢參數。
  • ignoreMethod:Boolean,false。true 時忽略請求方法(GET/HEAD)匹配。
  • ignoreVary:Boolean,false。true 時忽略 Vary 頭匹配。(什麼是Vary)
  • cacheName:String。表示所要搜索的緩存名稱。若是不設置則全局搜索,查找到第一個,當即返回。

Cache 方法

Cache 是 CacheStorage 的存儲實現,以 Request 作爲 key,以 Response 作爲 value 來進行存儲。能夠經過 CacheStorage.open(cacheName) 打開 Cache 來進行操做。

Cache 數據生成後,將會一直存在,修改/刪除 須要經過腳本本身去實現。

注: 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中
});
複製代碼

參數:

  • request:你想添加的 Request
  • response:你想添加匹配 Request 的 Response

注: request 參數,method 只支持 GET,不然會出現「TypeError: Request method POST is unsupported」 錯誤。

delete

刪除匹配 request key 的 cache ,找到並刪除成功 resolve(true)。

語法:

cache.delete(request,{options}).then(boolean => {
  // true: 你的 cache 已經刪除
});
複製代碼

參數:

request: 請求刪除的 Request。 options:(可選) 控制刪除搜索 key 如何去匹配(同 match 方法)。

  • ignoreSearch:Boolean,false。匹配時,是否忽略 url 的查詢參數。
  • ignoreMethod:Boolean,false。true 時忽略請求方法(GET/HEAD)匹配。
  • ignoreVary:Boolean,false。true 時忽略 Vary 頭匹配。(什麼是Vary)

add

給定 request 參數,自動請求獲取 response,並填入 cache 對象中。 等於 fetch + cache.put

注: response status 爲 opaque 的不能經過 add 方法添加,返回 reject。

語法:

cache.add(request).then(() => {
  // request 已經添加到 cache
});
複製代碼

addAll

和 Cache.add 做用相同,參數爲 request 的數組。

注: 只有在全部 requests 都成功的狀況下,才能完成 cache 緩存。

語法:

cache.addAll(requests[]).then(() => {
  // 全部 requests 都添加到 cache 。
});
複製代碼

match

返回匹配 request key 的第一個 cache。

注: 即便沒有匹配到,也將返回 resolve,只是值爲 undefined。

語法:

cache.match(request, {options}).then(response => {
  // 對 response 作一些處理
});
複製代碼

參數:

request: 請求匹配的 Request。 options:(可選) 控制搜索 key 如何去匹配(同 match 方法)。

  • ignoreSearch:Boolean,false。匹配時,是否忽略 url 的查詢參數。
  • ignoreMethod:Boolean,false。true 時忽略請求方法(GET/HEAD)匹配。
  • ignoreVary:Boolean,false。true 時忽略 Vary 頭匹配。(什麼是Vary)

matchAll

做用同 Cache.match,區別在於 Cache.match 返回匹配的 responses[0],而 Cache.matchAll 返回全部匹配的 responses 數組。

語法:

cache.matchAll(request,{options}).then(responses => {
  // 對 responses 數組作一些處理
});
複製代碼

參數:

request: 請求匹配的 Request。 options:(可選) 控制搜索 key 如何去匹配(同 match 方法)。

  • ignoreSearch:Boolean,false。匹配時,是否忽略 url 的查詢參數。
  • ignoreMethod:Boolean,false。true 時忽略請求方法(GET/HEAD)匹配。
  • ignoreVary:Boolean,false。true 時忽略 Vary 頭匹配。(什麼是Vary)

keys

返回當前 cache 實例下全部的 key。

注: 具備相同URL但不一樣請求頭的請求,若是它們的響應頭中有 VARY 頭部,則他們能夠被返回。

語法:

cache.keys(request,{options}).then(keys => {
  // 對 requests 作一些處理
});
複製代碼

參數:

request:(可選) 若是一個相關 Request key 被指定,則返回對應的 Request。 options:(可選) 控制搜索 key 如何去匹配(同 match 方法)。

  • ignoreSearch:Boolean,false。匹配時,是否忽略 url 的查詢參數。
  • ignoreMethod:Boolean,false。true 時忽略請求方法(GET/HEAD)匹配。
  • ignoreVary:Boolean,false。true 時忽略 Vary 頭匹配。(什麼是Vary)

調試查看

能夠經過 Chrome 的 DevTools進行查看。

Application → Cache → Cache Storage

Cache Storage 中是以 caches.open 建立的 cacheName 的 cache,右側列表中是經過 put/add/addAll 添加的 request key,點擊能夠在下方查看相關的 request 和 response。

緩存空間問題

web 端的離線存儲方式有三種,分別是:

  • Temporary
  • Persistent
  • Unlimited

而 Cache 屬於 Temporary 類型。Temporary 存儲是一種臨時存儲,任何Web應用程序均可以在沒有前期配額請求或用戶提示的狀況下使用,但存儲的數據能夠被瀏覽器隨時刪掉(佔用空間過多時,自動清理)。能夠類比於文件系統的 / tmp 目錄。

在 Chrome 和 Opera 中可使用新的實驗性 API 向設備請求持久化存取權限:

navigator.storage.persist().then(isGranted => {
	// true : 受權
})
複製代碼

各瀏覽器的離線空間:

  • 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

實際數據可經過 Quota Management API 來查看。

常見問題

跨域緩存

對於跨域緩存,跨域的資源須要開啓 Access-Control-Allow-Origin 頭部,而且 Request 的 mode 須要設置爲 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 設置爲 no-cors,但會致使 response 的 status 爲 0 的 opaque 響應,後面會講。

POST 緩存

因 Cache 中的規範指出只能存儲 GET 類型的 Request,因此想緩存 POST 類型的 Request 怎麼辦呢?

這裏建議兩種方式:

  1. 將 Response 進行序列化,或者將實際數據提取,放到 IndexDB 中進行存儲,監聽 fetch 事件的時候,匹配 IndexDB 來查找響應,並生成 Response 實例。
  2. 一些特殊的 POST 請求,如內容都是固化好的參數,一般不會發生變化,而且 URL 中有惟一性的標誌,則能夠在 fetch 中監聽到這種特殊 POST 時,把其轉化爲 GET 的 Request 來作爲 cache 的 key,等 Response 收到後,把 POST 的 Response 作爲轉化出來的 GET key 的 value 來存儲,便可實現。

opaque 不透明響應緩存

針對 response 的 status 爲 0 的 opaque 響應資源,也是能夠存儲到 cache 中的,可是並不建議存儲。由於響應狀態是 0,並不能確認資源是否完整及正確,緩存下來後,在 cache 中也是沒法查看其長度大小的,而且會致使一些存儲問題。

而且,忽然間 Cache Storage 變成了 10.3MB。
但存儲的這個 opaque 狀態的響應實際只有幾 kb,但緩存起來卻達到好幾 MB 這是什麼緣由呢?

其實這是 Chrome 瀏覽器層爲防止出現安全問題,因此把全部 opaque 狀態的請求都以這種幾 MB 的方式進行填充來保證安全的。

因此針對 opaque 狀態的請求,建議:

  • 不進行 opaque 狀態類型的緩存。
  • 對 opaque 狀態類弄的緩存添加 Access-Control-Allow-Origin 頭來實現狀態透明。

瀏覽器兼容性


博客名稱:王樂平博客

CSDN博客地址:blog.csdn.net/lecepin

知識共享許可協議
本做品採用 知識共享署名-非商業性使用-禁止演繹 4.0 國際許可協議進行許可。
相關文章
相關標籤/搜索