Progressive Web App (PWA)是渐进增强 Web App,它能让我们在不可靠的网络上也能快速加载、能够接收桌面通知、具有桌面图标,并且可采用顶层全屏体验的方式加载。
在 PWA 学习笔记之 fetch API 这篇文章中,我们介绍 fetch API 相关的一些基础知识,在该文章末尾我们还介绍了它在 PWA 应用中的使用场景,在具体的使用示例中,我们应用了 CacheStorage API。CacheStorage API(缓存存储应用程序接口),顾名思义是用来实现资源存储。该接口提供缓存 Request
/ Response
对象对的存储机制,尽管它被定义在 service worker 的标准中,但它不一定要配合 service worker 使用,接下来我们就来会一会 CacheStorage API。
首先我们来回顾一下 fetch API 文章中使用的示例:
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((response) => {
// 若缓存不存在,则使用fetch API从网上获取,然后利用Cache API缓存资源。
return response || fetch(event.request).then((response) => {
return caches.open('v1').then((cache) => {
cache.put(event.request, response.clone());
return response;
});
});
})
);
});
这个示例中,我们监听页面的 fetch 事件,对页面请求事件进行拦截,然后使用 event.respondWith 设置响应对象。在设置响应对象时,我们会优先从缓存中获取,若请求命中,则直接从缓存中获取已缓存的对象,直接返回。若请求未命中,则通过 fetch API 从远程获取对应的资源,当资源请求成功时,我们通过 open 方法获取 v1 版本的 CacheStorage 实例,然后调用该实例的 put 方法,进行资源缓存。
这里需要注意的是,在使用 cache对象的 put 方法保存资源时,我们调用 response 对象的 clone 方法,而不是直接保存 response 对象。为什么需要克隆响应对象呢?这是因为 Request 和 Response 的 body (响应体)只能被读取一次!它们有一个属性叫 bodyUsed,读取一次之后设置为 true,就不能再读取了。
通过上面的示例,我们简单介绍了 CacheStorage API 中的一些常用方法。接下来我们趁热打铁,来系统地了解一下目前 CacheStorage 已有的 API。
CacheStorage API 简介
- CacheStorage.match():返回一个 Promise 对象,用于判断给定的请求对象是否已被缓存。若匹配则返回已缓存的对象。
caches.match(request, options).then(function(response) {
// Do something with the response
});
- CacheStorage.has():返回一个 Promise 对象,用于判断 cacheName 对应的 Cache 对象是否存在。若 cacheName 对应的 Cache 对象存在,则返回 true 否则返回 false。
caches.has(cacheName).then(function(boolean) {
// true: 缓存存在
});
- CacheStorage.open():返回一个 Promise 对象,用于获取 cacheName 对应的 Cache 对象。若 cacheName 对应的 Cache 存在则返回对应的 Cache 对象,若不存在的话,则会创建一个新的 Cache 对象。
caches.open(cacheName).then(function(cache) {
// Do something with your cache
});
- CacheStorage.delete():返回一个 Promise 对象,用于删除 cacheName 对应的 Cache 对象。若 cacheName 对应的 Cache 对象存在且被成功删除,则返回 true,否则返回 false。
caches.delete(cacheName).then(function(true) {
//your cache is now deleted
});
- CacheStorage.keys():返回一个 Promise 对象,用于获取 CacheStorage 对象中已存在的缓存名称列表。
caches.keys().then(function(keyList) {
//do something with your keyList
});
CacheStorage API 使用示例
CacheStorage.match()
caches.match(event.request).then(function(response) {
return response || fetch(event.request).then(function(r) {
caches.open('v1').then(function(cache) {
cache.put(event.request, r);
});
return r.clone();
});
}).catch(function() {
return caches.match('/sw-test/gallery/myLittleVader.jpg');
});
CacheStorage.has()
caches.has('v1').then(function(hasCache) {
if (!hasCache) { // v1对应的Cache对象不存在
someCacheSetupfunction();
} else {
caches.open('v1').then(function(cache) {
return cache.addAll(myAssets);
});
}
}).catch(function() {
// 处理异常
});
CacheStorage.open()
var cachedResponse = caches.match(event.request)
.catch(function() {
return fetch(event.request);
}).then(function(response) {
caches.open('v1').then(function(cache) {
cache.put(event.request, response);
});
return response.clone();
}).catch(function() {
return caches.match('/sw-test/gallery/myLittleVader.jpg');
});
CacheStorage.delete() & caches.keys()
this.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) { // 删除不含有v2的缓存对象
return caches.delete(key);
}
}));
})
);
});
以上 CacheStorage API 相关示例来源于 MDN - CacheStorage 缓存存储。
一口气分析完了 CacheStorage 相关的 API,不知道小伙伴有没有疑问。感觉对刚了解 PWA 的小伙伴们来说,会对示例中所使用的 fetch
或 activate
事件感到疑惑,这个不用着急。接下来的文章我们会来揭开它们神秘的面纱。
本文介绍了 CacheStorage API 的相关基础知识,最后我们来介绍一个小知识 —— 如何查看已缓存的资源?其实这个很简单,容我偷个懒,这里只介绍 Chrome 浏览器如何查看。准备好了么?Follow Me!
- 打开 Chrome 浏览器
- 打开开发者工具
- 切换到 Application Tab 页
- 选择左侧 Cache 菜单下的 CacheStorage 选项
初探 CacheStorage API 到此结束,下一篇就是介绍我们的 Service Workers 了,它可是 PWA 的核心 “人物 ” 哟。目前刚开始学习 PWA,有误之处,请小伙伴们多多指教。
够专业!
Downvoting a post can decrease pending rewards and make it less visible. Common reasons:
Submit
哈哈,这阵子刚开始学习,18年前端的发展趋势。
Downvoting a post can decrease pending rewards and make it less visible. Common reasons:
Submit