騰訊雲技術社區-掘金主頁持續爲你們呈現雲計算技術文章,歡迎你們關注!javascript
做者:villainthrcss
Service Worder 是用來代替 manifest,用來生成緩存的效果的。之前吭哧吭哧的學 manifest 的時候,就發現 MD 好難用。並且 MDN 特地告訴你,manifest 有毒,請不要亂用,保不定後面不支持。今兒,我看了下兼容性,呵呵~html
人生苦短,及時享樂,前端真坑,不敢亂學。前端
前方高能,若是以爲生活沒有趣味能夠繼續看下去,會讓你的人生更沒有趣味。若是以爲湊合能過,請 ctrl/command + w
。java
繼續~node
Service Worker 講道理是由兩部分構成,一部分是 cache,還有一部分則是 Worker。因此,SW(Service Worker) 自己的執行,就徹底不會阻礙當前 js 進程的執行,確保性能第一。那 SW 究竟是怎麼工做的呢?git
咱們先來看看 SW 比較坑的地方,它的 lifecyclegithub
首先,SW 並非你網頁加載就與生俱來的。若是,你須要使用 SW,你首先須要註冊一個 SW,讓瀏覽器爲你的網頁分配一塊內存空間來。而且,你可否註冊成功,還須要看你緩存的資源量決定(有可能失敗,真的有可能)。若是,你須要緩存的靜態資源所有保存成功,那麼恭喜您,SW 安裝成功。若是,其中有一個資源下載失敗而且沒法緩存,那麼此次吊起就是失敗的。不過,SW 是由重試機制的,這點也不算特別坑。web
當安裝成功以後,此時 SW 就進入了激活階段(activation)。而後,你能夠選擇性的檢查之前的文件是否過時等。ajax
檢查完以後,SW 就進入待機狀態。此時,SW 有兩種狀態,一種是 active,一種是 terminated。就是激活/睡眠。激活是爲了工做,睡眠則爲了節省內存。這是一開始設計的初衷。若是,SW 已經 OK,那麼,你網頁的資源都會被 SW 控制,固然,SW 第一次加載除外。
簡單的流程圖,能夠參考一下 google的:
上面簡單介紹了 SW 的基本生命週期(實際上,都是廢話),講點實在的,它的兼容性咋樣?
基本上手機端是能用的。
如今,開發一個網站沒用 HTTPS,估計都沒好意思放出本身的域名(太 low)。HTTPS 不只僅能夠保證你網頁的安全性,還可讓一些比較敏感的 API 完美的使用。值得一提的是,SW 是基於 HTTPS 的,因此,若是你的網站不是 HTTPS,那麼基本上你也別想了 SW。這估計形成了一個困難,即,我調試 SW 的時候咋辦?
解決辦法也是有的,使用 charles
或者 fildder
完成域名映射便可。
下面,咱們仔細介紹下,SW 的基本使用。
SW 其實是掛載到 navigator 下的對象。在使用以前,咱們須要先檢查一下是否可用:
if ('serviceWorker' in navigator) {
// ....
}複製代碼
若是可用,咱們就要使用 SW 進行路由的註冊緩存文件了。不過,這裏有點爭議。啥時候開始執行 SW 的註冊呢?上面說過,SW 就是一個網絡代理,用來捕獲你網頁的全部 fetch 請求。那麼,是否是能夠這麼寫?
window.addEventListener('DOMContentLoaded', function() {
// 執行註冊
navigator.serviceWorker.register('/sw.js').then(function(registration) {
}).catch(function(err) {
});
});複製代碼
這樣理解邏輯上是沒有任何問題的,關鍵在於,雖然 SW 是 worker ,但瀏覽器的資源也是有限的,瀏覽器分配給你網頁的內存就這麼多,你再開個 SW(這個很大的。。。),沒有 jank 纔怪嘞,並且若是你網頁在一開始加載的時候有動畫展現的話,那麼這種方式基本上就 GG 了。
另外,若是算上用戶第一次加載,那麼這個卡頓或者延時就很大了。
固然,W3C 在制定相關規範時,確定考慮到這點,實際上 SW 在你網頁加載完成一樣也能捕獲已經發出的請求。因此,爲了減小性能損耗,咱們通常直接在 onload 事件裏面註冊 SW 便可。GOOGLE Jeff Posnick
針對這個加載,專門討論了一下,有興趣的能夠參考一下。(特別提醒,若是想要測試註冊 SW 可使用隱身模式調試!!!)
那當我註冊成功時,怎樣查看我註冊的 SW 呢?
這很簡單,直接打開 chrome://inspect/#service-workers 就能夠查看,在當前瀏覽器中,正在註冊的 SW。另外,還有一個 chrome://serviceworker-internals,用來查看當前瀏覽器中,全部註冊好的 SW。
使用 SW 進行註冊時,還有一個很重要的特性,即,SW 的做用域不一樣,監聽的 fetch 請求也是不同的。
例如,咱們將註冊路由換成: /example/sw.js
window.addEventListener('DOMContentLoaded', function() {
// 執行註冊
navigator.serviceWorker.register('/example/sw.js').then(function(registration) {
}).catch(function(err) {
});
});複製代碼
那麼,SW 後面只會監聽 /example
路由下的全部 fetch 請求,而不會去監聽其餘,好比 /jimmy
,/sam
等路徑下的。
從這裏開始,咱們就正式進入 SW 編程。記住,下面的部分是在另一個 js 中的腳本,使用的是 worker 的編程方法。若是,有同窗還不理解 worker 的話,能夠先去學習一下,這樣在後面的學習中才不會踩很深的坑。
監聽安裝 SW 的代碼也很簡單:
self.addEventListener('install', function(event) {
// Perform install steps
});複製代碼
當安裝成功後,咱們能使用 SW 作什麼呢?
那就開始緩存文件了唄。簡單的例子爲:
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open('mysite-static-v1').then(function(cache) {
return cache.addAll([
'/css/whatever-v3.css',
'/css/imgs/sprites-v6.png',
'/css/fonts/whatever-v8.woff',
'/js/all-min-v4.js'
]);
})
);
});複製代碼
此時,SW 會檢測你制定文件的緩存問題,若是,已經都緩存了,那麼 OK,SW 安裝成功。若是查到文件沒有緩存,則會發送請求去獲取,而且會帶上 cache-bust
的 query string,來表示緩存的版本問題。固然,這隻針對於第一次加載的狀況。當全部的資源都已經下載成功,那麼恭喜你能夠進行下一步了。你們能夠參考一下 google demo。
這裏,我簡單說一下上面的過程,首先 event.waitUntil
你能夠理解爲 new Promise,它接受的實際參數只能是一個 promise,由於,caches 和 cache.addAll 返回的都是 Promise,這裏就是一個串行的異步加載,當全部加載都成功時,那麼 SW 就能夠下一步。另外,event.waitUntil 還有另一個重要好處,它能夠用來延長一個事件做用的時間,這裏特別針對於咱們 SW 來講,好比咱們使用 caches.open 是用來打開指定的緩存,但開啓的時候,並非一下就能調用成功,也有可能有必定延遲,因爲系統會隨時睡眠 SW,因此,爲了防止執行中斷,就須要使用 event.waitUntil 進行捕獲。另外,event.waitUntil 會監聽全部的異步 promise,若是其中一個 promise 是 reject 狀態,那麼該次 event 是失敗的。這就致使,咱們的 SW 開啓失敗。
不過,若是其中一個文件下載失敗的話,那麼此次你的 SW 啓動就告吹了,即,若是其中有一個 Promise 是使用 reject 的話,那就表明着--您此次啓動是 GG 的。那,有沒有其餘辦法在保證必定穩定性的前提下,去加載比較大的文件呢?
有的,那你別返回 cache.addAll 就ok了。什麼個意思呢?
就這樣:
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open('mygame-core-v1').then(function(cache) {
// 不穩定文件或大文件加載
cache.addAll(
//...
);
// 穩定文件或小文件加載
return cache.addAll(
// core assets & levels 1-10
);
})
);
});複製代碼
這樣,第一個 cache.addAll
是不會被捕獲的,固然,因爲異步的存在,這毋庸置疑會有一些問題。好比,當大文件還在加載的時候,SW 斷開,那麼此次請求就是無效的。不過,你這樣寫原本就算是一個 trick,這種狀況在制定方案的時候,確定也要考慮進去的。整個步驟,咱們能夠用下圖表示:
FROM GOOGLE
該階段就是事關整個網頁可否正常打開的一個階段--很是關鍵。在這一階段,咱們將學會,如何讓 web 使用緩存,如何作向下兼容。
先看一個簡單的格式:
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request)
.then(function(response) {
// Cache hit - return response
if (response) {
return response;
}
return fetch(event.request);
}
)
);
});複製代碼
首先看一下,第一個方法--event.respondWith
,用來包含響應主頁面請求的代碼。當接受到 fetch 請求時,會直接返回 event.respondWith
Promise 結果。咱們在 worker 中,捕獲頁面全部的 fetch 請求。能夠看到 event.request
,這個就是 fetch 的 request 流。咱們經過 caches.match 捕獲,而後返回 Promise 對象,用來進行響應的處理。你們看這段代碼時,可能會有不少的疑惑,是的,一開始我看的時候也是,由於,根本沒註釋,有些 name
其實是內核自帶的。上面的就有:
簡單來講,caches.match 根據 event.request
,在緩存空間中查找指定路徑的緩存文件,若是匹配到,那麼 response
是有內容的。若是沒有的話,則再經過 fetch 進行捕獲。整個流圖以下:
OK,那如今有個問題,若是沒有找到緩存,那麼應該怎麼作呢?
那怎麼手動添加呢?
很簡單,本身發送 fetch,而後使用 caches
進行緩存便可。不過,這裏又涉及到另一個概念,Request 和 Response 流。這是在 fetch 通訊方式 很重要的兩個概念。fetch 不只分裝了 ajax,並且在通訊方式上也作了進一步的優化,同 node 同樣,使用流來進行重用。衆所周知,一個流通常只能使用一次,能夠理解爲喝礦泉水,只能喝一次,不過,若是我知道了該水的配方,那麼我就能夠量產該水,這就是流的複製。下面代碼也基本使用到這兩個概念,基本代碼爲:
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request)
.then(function(response) {
if (response) {
return response;
}
// 由於 event.request 流已經在 caches.match 中使用過一次,
// 那麼該流是不能再次使用的。咱們只能獲得它的副本,拿去使用。
var fetchRequest = event.request.clone();
// fetch 的經過信方式,獲得 Request 對象,而後發送請求
return fetch(fetchRequest).then(
function(response) {
// 檢查是否成功
if(!response || response.status !== 200 || response.type !== 'basic') {
return response;
}
// 若是成功,該 response 一是要拿給瀏覽器渲染,而是要進行緩存。
// 不過須要記住,因爲 caches.put 使用的是文件的響應流,一旦使用,
// 那麼返回的 response 就沒法訪問形成失敗,因此,這裏須要複製一份。
var responseToCache = response.clone();
caches.open(CACHE_NAME)
.then(function(cache) {
cache.put(event.request, responseToCache);
});
return response;
}
);
})
);
});複製代碼
那麼整個流圖變爲:
而裏面最關鍵的地方就是 stream 這是如今瀏覽器操做數據的一個新的標準。爲了不將數據一次性寫入內存,咱們這裏引入了 stream,至關於一點一點的吐。這個和 nodeJS 裏面的 stream 是同樣的效果。你用上述哪一個流圖,這估計得取決於你本身的業務。
在 SW 中的更新涉及到兩塊,一個是基本靜態資源的更新,還有一個是 SW.js 文件的更新。這裏,咱們先說一下比較坑的 SW.js 的更新。
SW.js 的更新不只僅只是簡單的更新,爲了用戶可靠性體驗,裏面仍是有不少門道的。
install
事件被觸發waiting
狀態。注意,此時並不存在替換activate
事件。整個流程圖爲:
若是上述步驟成功後,原來的 SW.js 就會被清除。可是,之前版本 SW.js 緩存文件沒有被刪除。針對於這一狀況,咱們能夠在新的 SW.js 裏面監聽 activate 事件,進行相關資源的刪除操做。固然,這裏主要使用到的 API 和 caches 有很大的關係(由於,如今全部緩存的資源都在 caches 的控制下了)。好比,我之前的 SW 緩存的版本是 v1
,如今是 v2
。那麼我須要將 v1
給刪除掉,則代碼爲:
self.addEventListener('activate', function(event) {
var cacheWhitelist = ['v1'];
event.waitUntil(
// 遍歷 caches 裏全部緩存的 keys 值
caches.keys().then(function(cacheNames) {
return Promise.all(
cacheNames.map(function(cacheName) {
if (cacheWhitelist.includes(cacheName)) {
// 刪除 v1 版本緩存的文件
return caches.delete(cacheName);
}
})
);
})
);
});複製代碼
另外,我那麼你不經僅能夠用來做爲版本的更新,還能夠做爲緩存目錄的替換。好比,我想直接將 site-v1
的緩存文件,替換爲 ajax-v1
和 page-v1
。則,咱們一是須要先在 install
事件裏面將 ajajx-v1
和 page-v1
緩存套件給註冊了,而後,在 activate 裏面將 site-v1
緩存給刪除,實際代碼和上面實際上是同樣的:
self.addEventListener('activate', function(event) {
var cacheWhitelist = ['site-v1'];
event.waitUntil(
// 遍歷 caches 裏全部緩存的 keys 值
caches.keys().then(function(cacheNames) {
return Promise.all(
cacheNames.map(function(cacheName) {
if (cacheWhitelist.includes(cacheName)) {
// 刪除 v1 版本緩存的文件
return caches.delete(cacheName);
}
})
);
})
);
});複製代碼
OK,SW.js 更新差很少就是這樣一塊內容。
對於文件更新來講,整個機制就顯得很簡單了。能夠說,你想要一個文件更新,只須要在 SW 的 fetch
階段使用 caches 進行緩存便可。實際操做也很簡單,一開始咱們的 install
階段的代碼爲:
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open('mysite-static-v1').then(function(cache) {
return cache.addAll([
'/css/whatever-v3.css',
'/css/imgs/sprites-v6.png',
'/css/fonts/whatever-v8.woff',
'/js/all-min-v4.js'
]);
})
);
});複製代碼
咱們只須要在這裏簡單的寫下一下 prefetch 代碼便可。
self.addEventListener('install', function(event) {
var now = Date.now();
// 事先設置好須要進行更新的文件路徑
var urlsToPrefetch = [
'static/pre_fetched.txt',
'static/pre_fetched.html',
'https://www.chromium.org/_/rsrc/1302286216006/config/customLogo.gif'
];
event.waitUntil(
caches.open(CURRENT_CACHES.prefetch).then(function(cache) {
var cachePromises = urlsToPrefetch.map(function(urlToPrefetch) {
// 使用 url 對象進行路由拼接
var url = new URL(urlToPrefetch, location.href);
url.search += (url.search ? '&' : '?') + 'cache-bust=' + now;
// 建立 request 對象進行流量的獲取
var request = new Request(url, {mode: 'no-cors'});
// 手動發送請求,用來進行文件的更新
return fetch(request).then(function(response) {
if (response.status >= 400) {
// 解決請求失敗時的狀況
throw new Error('request for ' + urlToPrefetch +
' failed with status ' + response.statusText);
}
// 將成功後的 response 流,存放在 caches 套件中,完成指定文件的更新。
return cache.put(urlToPrefetch, response);
}).catch(function(error) {
console.error('Not caching ' + urlToPrefetch + ' due to ' + error);
});
});
return Promise.all(cachePromises).then(function() {
console.log('Pre-fetching complete.');
});
}).catch(function(error) {
console.error('Pre-fetching failed:', error);
})
);
});複製代碼
當成功獲取到緩存以後, SW 並不會直接進行替換,他會等到用戶下一次刷新頁面事後,使用新的緩存文件。
不過,這裏請注意,我並無說,咱們更新緩存只能在 install
裏更新,事實上,更新緩存能夠在任何地方執行。它主要的目的是用來更新 caches 裏面緩存套件。咱們提取一下代碼:
// 找到緩存套件並打開
caches.open(CURRENT_CACHES.prefetch).then(function(cache) {
// 根據事先定義的路由開始發送請求
var cachePromises = urlsToPrefetch.map(function(urlToPrefetch) {
// 執行 fetch
return fetch(request).then(function(response) {
// 緩存請求到的資源
return cache.put(urlToPrefetch, response);
}).catch(function(error) {
console.error('Not caching ' + urlToPrefetch + ' due to ' + error);
});
});
// 使用 promise.all 進行所有捕獲
return Promise.all(cachePromises).then(function() {
console.log('Pre-fetching complete.');
});
}).catch(function(error) {
console.error('Pre-fetching failed:', error);
})複製代碼
如今,咱們已經拿到了核心代碼,那有沒有什麼簡便的辦法,讓咱們少寫一些配置項,直接對每個文件進行文件更新教研。
有的!!!
還記得上面的 fetch
事件嗎?咱們簡單回顧一下它的代碼:
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request)
.then(function(response) {
// Cache hit - return response
if (response) {
return response;
}
return fetch(event.request);
}
)
);
});複製代碼
實際上,咱們能夠將上面的核心代碼作一些變化直接用上:
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.open('mysite-dynamic').then(function(cache) {
return cache.match(event.request).then(function(response) {
var fetchPromise = fetch(event.request).then(function(networkResponse) {
cache.put(event.request, networkResponse.clone());
return networkResponse;
})
return response || fetchPromise;
})
})
);
});複製代碼
這裏比較難的地方在於,咱們並無去捕獲 fetch(fetchRequest)... 相關內容。也就是說,這一塊是徹底獨立於咱們的主體業務的。他的 fetch 只是用更新文件而已。咱們可使用一個流圖進行表示:
ok,關於文件的緩存咱們就介紹到這裏。
如今,爲了更好的用戶體驗,咱們能夠作的更尊重用戶一些。能夠設置一個 button,告訴用戶是否選擇緩存指定文件。有同窗可能會想到使用 postmessage API,來告訴 SW 執行相關的緩存信息。不過事實上,還有更簡單的辦法來完成,即,直接使用 caches 對象。caches 和 web worker 相似。都是直接掛載到 window 對象上的。因此,咱們能夠直接使用 caches 這個全局變量來進行搜索。那麼該環節就不須要直接經過 SW,這個流程圖能夠畫爲:
代碼能夠參考:
document.querySelector('.cache-article').addEventListener('click', function(event) {
event.preventDefault();
var id = this.dataset.articleId;
// 建立 caches 套件
caches.open('mysite-article-' + id).then(function(cache) {
fetch('/get-article-urls?id=' + id).then(function(response) {
// 返回 json 對象
return response.json();
}).then(function(data) {
// 緩存指定路由
cache.addAll(data);
});
});
});複製代碼
這裏我就不贅述了,簡單來講就是更新一下緩存。
上面大體瞭解了一下關於 SW 的基本流程,不過說到底,SW 只是一個容器,它的內涵只是一個駐留後臺進程。咱們想關心的是,在這進程裏面,咱們能夠作些什麼?
最主要的應該有兩個東西,緩存和推送。這裏咱們主要講解一下緩存。不過在SW 中,咱們通常只能緩存 POST
上面在文件更新裏面也講了幾個更新的方式。簡單來講:
簡單的情形上面已經說了,我這裏專門將一下比較複雜的內容。
這種情形通常是用來裝逼的,一方面檢查請求,一方面有檢查緩存,而後看兩個誰快,就用誰,我這裏直接上代碼吧:
function promiseAny(promises) {
return new Promise((resolve, reject) => {
// 經過 promise 的 resolve 特性來決定誰快
promises = promises.map(p => Promise.resolve(p));
// 這裏調用外層的 resolve
promises.forEach(p => p.then(resolve));
// 若是其中有一方出現 error,則直接掛掉
promises.reduce((a, b) => a.catch(() => b))
.catch(() => reject(Error("All failed")));
});
};
self.addEventListener('fetch', function(event) {
event.respondWith(
promiseAny([
caches.match(event.request),
fetch(event.request)
])
);
});複製代碼
這裏就和咱們在後臺配置的 Last-Modifier || Etag 同樣,詢問更新的文件內容,而後執行更新:
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.open('mysite-dynamic').then(function(cache) {
return fetch(event.request).then(function(response) {
cache.put(event.request, response.clone());
return response;
});
})
);
});複製代碼
這應該是目前爲止最佳的體驗,返回的時候不會影響正在發送的請求,而接受到的新的請求後,最新的文件會替換舊的文件。(這個就是前面寫的代碼):
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.open('mysite-dynamic').then(function(cache) {
return cache.match(event.request).then(function(response) {
var fetchPromise = fetch(event.request).then(function(networkResponse) {
cache.put(event.request, networkResponse.clone());
return networkResponse;
})
return response || fetchPromise;
})
})
);
});複製代碼
接下來,咱們來詳細瞭解一下關於 Cache Object 相關的內容。加深印象:
Cache 雖然是在 SW 中定義的,可是咱們也能夠直接在 window 域下面直接使用它。它經過 Request/Response 流(就是 fetch)來進行內容的緩存。每一個域名能夠有多個 Cache Object,具體咱們能夠在控制檯中查看:
而且 Cache Object 是懶更新,實際上,就能夠把它比喻爲一個文件夾。若是你不本身親自更新,系統是不會幫你作任何事情的。對於刪除也是同樣的道理,若是你不顯示刪除,它會一直存在的。不過,瀏覽器對於每一個域名的 Cache Object 數量是有限制的,而且,會週期性的刪掉一些緩存信息。最好的辦法,是咱們本身管理資源,官方給出的建議是: 使用版本號進行資源管理。上面我也展現過,刪除特定版本的緩存資源:
self.addEventListener('activate', function(event) {
var cacheWhitelist = ['v2'];
event.waitUntil(
caches.keys().then(function(keyList) {
return Promise.all(keyList.map(function(key) {
if (cacheWhitelist.indexOf(key) === -1) {
return caches.delete(key);
}
}));
})
);
});複製代碼
這裏,咱們就能夠將 Cache Object 理解爲一個持久性數據庫,那麼針對於數據庫來講,簡單的操做就是 CRUD。而 Cache Object 也提供了這幾個接口,而且接口結果都是經過 Promise 對象返回的,成功返回對應結果,失敗則返回 undefined:
http://foo.com/?value=bar
,咱們不會再搜索 ?value=bar
這幾個字符。cache.match(request,{options}).then(function(response) {
//do something with the response
});複製代碼
cache.matchAll(request,{options}).then(function(response) {
response.forEach(function(element, index, array) {
cache.delete(element);
});
});複製代碼
cache.add(url).then(function() {
// 請求的資源被成功緩存
});
# 等同於
fetch(url).then(function (response) {
if (!response.ok) {
throw new TypeError('bad response status');
}
return cache.put(url, response);
})
.then(res=>{
// 成功緩存
})複製代碼
this.addEventListener('install', function(event) {
event.waitUntil(
caches.open('v1').then(function(cache) {
return cache.addAll([
'/public/',
'/public/index.html',
'/public/style.css',
'/public/app.js'
]);
})
);
});複製代碼
cache.put(request, response).then(function() {
// 成功緩存
});複製代碼
cache.keys().then(function(keys) {
keys.forEach(function(request, index, array) {
cache.delete(request);
});
});複製代碼
能夠查看到上面的參數都共同的用到了 request
這就是 fetch 套件裏面的請求流,具體,能夠參考一下前面的代碼。上面全部方法都是返回一個 Promise 對象,用來進行異步操做。
上面簡單介紹了一下 Cache Object,但實際上,Cache 的管理方式是兩級管理。即,最外層是 Cache Storage
,下一層是 Cache Object
。
瀏覽器會給每一個域名預留一個 Cache Storage(只有一個)。而後,剩下的緩存資源,所有都存在下面。咱們能夠理解爲,這就是一個頂級緩存目錄管理。而咱們獲取 Cache Object 的惟一途徑,就是經過 caches.open() 進行獲取。這裏,咱們就能夠將 open 方法理解爲 沒有已經存在的 Cache Object 則新建,不然直接打開
。它的相關操做方法也有不少:
caches.match(event.request).then(function(resp) {
return resp || fetch(event.request).then(function(r) {
caches.open('v1').then(function(cache) {
cache.put(event.request, r);
});
return r.clone();
});
});複製代碼
caches.has('v1').then(function(hasCache) {
// 檢測是否存在 Cache Object Name 爲 v1 的緩存內容
if (!hasCache) {
// 沒存在
} else {
//...
}
}).catch(function() {
// 處理異常
});複製代碼
caches.open('v1').then(function(cache) {
cache.add('/index.html');
});複製代碼
caches.delete(cacheName).then(function(isDeleted) {
// 檢測是否刪除成功
});
# 經過,能夠經過 Promise.all 的形式來刪除多個 cache object
Promise.all(keyList.map(function(key) {
if (cacheList.indexOf(key) === -1) {
return caches.delete(keyList[i]);
}
});複製代碼
event.waitUntil(
caches.keys().then(function(keyList) {
return Promise.all(keyList.map(function(key) {
if (['v1','v2'].indexOf(key) === -1) {
return caches.delete(keyList[i]);
}
});
})
);複製代碼
上面就是關於 Cache Storage 的全部內容。
這裏放一張本身寫的總結圖吧:
相關推薦
React 同構思想
Vue.js先後端同構方案之準備篇——代碼優化
Vue組件開發實踐之scopedSlot的傳遞
此文已由做者受權騰訊雲技術社區發佈,轉載請註明文章出處
原文連接:www.qcloud.com/community/a…
獲取更多騰訊海量技術實踐乾貨,歡迎你們前往騰訊雲技術社區