CacheStorage - 表示 Cache 对象的存储
CacheStorage 接口表示 Cache 对象的存储。
该接口:
- 提供可以由
ServiceWorker或其他类型的工作线程或window范围访问的所有命名缓存的主目录(虽然是 Service Workers 规范对其进行了定义,但是除了服务工作线程之外,您还可以与其他的功能一起使用它。)注意:Chrome 和 Safari 在 HTTPS 中向窗口上下文提供
CacheStorage接口。除非配置了 SSL 证书,否则window.caches将是未定义的。 - 维护字符串名称到相应的
Cache对象的映射。
使用 CacheStorage.open() 获得 Cache 实例。
使用 CacheStorage.match() 来检查给定的 Request 是否是 CacheStorage 对象跟踪的任何 Cache 对象中的键。
您可以通过全局 caches 属性访问 CacheStorage 。
注意:
CacheStorage总是在不受信任的来源(即那些不使用 HTTPS 的应用程序,尽管将来这种定义可能会变得更加复杂)上以SecurityError拒绝。在测试时,您可以通过检查 Firefox Devtools 选项 / 齿轮菜单中的 “通过 HTTP 启用 Service Workers(打开工具箱时)” 选项来解决此问题。
注意:
CacheStorage.match()是一个快捷方法。可以通过以下方式实现与缓存条目匹配的等效功能:从CacheStorage.keys()返回一组缓存名称,使用CacheStorage.open()打开每个缓存,然后使用Cache.match()匹配所需的缓存。
方法
CacheStorage.match()
检查给定的 Request 对象是否是 CacheStorage 对象跟踪的 Cache 对象中的键,返回一个 Promise,解析为该匹配项。
CacheStorage.has()
返回一个 Promise,如果存在与 cacheName 相匹配的Cache 对象,则解析为 true。
CacheStorage.open()
返回一个 Promise,它解析为与 cacheName 相匹配的 Cache 对象(如果尚不存在,则会创建一个新的缓存。)
CacheStorage.delete()
查找与 cacheName 匹配的 Cache 对象,如果找到,则删除 Cache 对象,并返回一个 Promise 解析为 true。如果没有找到 Cache 对象,则解析为 false 。
CacheStorage.keys()
返回一个 Promise,该数组将解析为包含与 CacheStorage 跟踪的所有命名 Cache 对象相对应的字符串的数组。使用此方法可以迭代所有 Cache 对象的列表。
实例
此代码段来自 sw-test 实例(请参阅 sw-test 在线运行。)此服务工作线程脚本等待 InstallEvent 触发,然后运行 waitUntil 来处理应用程序的安装过程。它包括调用 CacheStorage.open 创建新的缓存,然后使用 Cache.addAll 向其中添加一系列资源。
在第二个代码块中,我们等待 FetchEvent 触发。我们构造一个自定义响应,如下所示:
- 检查在
CacheStorage中是否找到与请求匹配的内容。如果是这样,那就处理它。 - 如果不是,那么从网络获取请求,然后再打开在第一个块中创建的缓存,并使用
Cache.put(cache.put(event.request, response.clone()))向其添加请求的副本。 - 如果失败(例如,由于网络中断),则返回一个后备响应。
最后,使用 FetchEvent.respondWith 返回自定义响应。
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open('v1').then(function(cache) {
return cache.addAll([
'/sw-test/',
'/sw-test/index.html',
'/sw-test/style.css',
'/sw-test/app.js',
'/sw-test/image-list.js',
'/sw-test/star-wars-logo.jpg',
'/sw-test/gallery/bountyHunters.jpg',
'/sw-test/gallery/myLittleVader.jpg',
'/sw-test/gallery/snowTroopers.jpg'
]);
})
);
});
self.addEventListener('fetch', function(event) {
event.respondWith(caches.match(event.request).then(function(response) {
// caches.match() 始终会解析,但如果成功,响应才有值
if (response !== undefined) {
return response;
} else {
return fetch(event.request).then(function (response) {
// 响应只能使用一次。我们需要保存克隆以将一个副本放入缓存并提供第二个副本
let responseClone = response.clone();
caches.open('v1').then(function (cache) {
cache.put(event.request, responseClone);
});
return response;
}).catch(function () {
return caches.match('/sw-test/gallery/myLittleVader.jpg');
});
}
}));
});
该代码段展示了如何在服务工作线程上下文之外使用 API,并使用 await 运算符来编写更具可读性的代码。
// 尝试从高速缓存中获取数据,如果没有则回退到获取实时数据。
async function getData() {
const cacheVersion = 1;
const cacheName = `myapp-${ cacheVersion }`;
const url = 'https://jsonplaceholder.typicode.com/todos/1';
let cachedData = await getCachedData( cacheName, url );
if ( cachedData ) {
console.log( '检索缓存的数据' );
return cachedData;
}
console.log( '获取新数据' );
const cacheStorage = await caches.open( cacheName );
await cacheStorage.add( url );
cachedData = await getCachedData( cacheName, url );
await deleteOldCaches( cacheName );
return cachedData;
}
// 从缓存中获取数据。
async function getCachedData( cacheName, url ) {
const cacheStorage = await caches.open( cacheName );
const cachedResponse = await cacheStorage.match( url );
if ( ! cachedResponse || ! cachedResponse.ok ) {
return false;
}
return await cachedResponse.json();
}
// 删除任何旧的缓存,给用户留出磁盘空间。
async function deleteOldCaches( currentCache ) {
const keys = await caches.keys();
for ( const key of keys ) {
const isOurCache = 'myapp-' === key.substr( 0, 6 );
if ( currentCache === key || ! isOurCache ) {
continue;
}
caches.delete( key );
}
}
try {
const data = await getData();
console.log( { data } );
} catch ( error ) {
console.error( { error } );
}
规范
| 规范 | 状态 | 备注 |
|---|---|---|
| Service Workers CacheStorage 的定义 |
工作草案 | 初始定义。 |
桌面浏览器兼容性
| 特性 | Chrome | Edge | Firefox | Internet Explorer | Opera | Safari |
|---|---|---|---|---|---|---|
| 基础支持 | 4012 | ≤18 | 443 | 不支持 | 27 | 11.1 |
delete | 40 | 16 | 443 | 不支持 | 27 | 11.1 |
has | 40 | 16 | 443 | 不支持 | 27 | 11.1 |
keys | 40 | 16 | 443 | 不支持 | 27 | 11.1 |
match | 54 406 | 16 | 443 | 不支持 | 41 276 | 11.1 |
open | 40 | 16 | 443 | 不支持 | 27 | 11.1 |
| Secure context required | 65 | ≤79 | 44 | 不支持 | 52 | 支持 |
移动浏览器兼容性
| 特性 | Android | Chrome for Android | Edge mobile | Firefox for Android | IE mobile | Opera Android | iOS Safari |
|---|---|---|---|---|---|---|---|
| 基础支持 | 4012 | 4012 | 未知 | 44 | 未知 | 27 | 支持 |
delete | 40 | 40 | 未知 | 44 | 未知 | 27 | 支持 |
has | 40 | 40 | 未知 | 44 | 未知 | 27 | 支持 |
keys | 40 | 40 | 未知 | 44 | 未知 | 27 | 支持 |
match | 54 406 | 54 406 | 未知 | 44 | 未知 | 41 276 | 支持 |
open | 40 | 40 | 未知 | 44 | 未知 | 27 | 支持 |
| Secure context required | 65 | 65 | 未知 | 44 | 未知 | 47 | 支持 |
1. 从版本 43 开始,可以从 Window 访问。
2. 从版本 43 开始,可以从 WorkerGlobalScope 访问。
3. 在 Firefox 45 和 52 扩展支持版本(ESR)中,服务工作线程(和 Push)已被禁用。
4. 从 Samsung Internet 4.0 开始,可以从 Window 访问。
5. 从 Samsung Internet 4.0 开始,可以从 WorkerGlobalScope 访问。
6. options 参数仅支持 ignoreSearch 和 cacheName。