缓存
注意:此功能在Web Workers中可用。
Cache
接口为在长期内存中缓存的 Request
/ Response
对象对提供了一种持久性存储机制。Cache
对象的生命周期取决于浏览器,但单个来源的脚本通常可以依赖于先前填充的 Cache
对象的存在。请注意,Cache
接口既公开给窗口范围,也公开给工作线程。即使它是在 Service Worker 规范中定义的,您也不必将其与 Service Worker 结合使用。
一个来源可以有多个命名的 Cache
对象。您负责实现您的脚本(例如,在ServiceWorker
中)如何处理 Cache
更新。除非显式请求,否则 Cache
中的项目不会更新;除非删除,否则它们不会过期。使用CacheStorage.open()
打开一个特定命名的 Cache
对象,然后调用任何 Cache
方法来维护 Cache
。
您还负责定期清除缓存条目。每个浏览器对给定来源可以使用的缓存存储量都有一个硬性限制。可以通过 StorageManager.estimate()
方法获得 Cache
配额使用情况的估算。浏览器会尽力管理磁盘空间,但它可能会删除来源的 Cache
存储。浏览器通常会删除来源的所有数据或不删除来源的任何数据。确保通过名称对缓存进行版本控制,并且仅从可以安全操作它们的脚本版本中使用缓存。有关更多信息,请参阅删除旧缓存。
注意:键匹配算法取决于值中的VARY 标头。因此,匹配新键需要查看 Cache
对象中条目的键和值。
注意:缓存 API 不遵守 HTTP 缓存标头。
实例方法
Cache.match()
-
返回一个
Promise
,该 Promise 解析为Cache
对象中第一个匹配请求关联的响应。 Cache.matchAll()
-
返回一个
Promise
,该 Promise 解析为Cache
对象中所有匹配响应的数组。 Cache.add()
-
获取 URL,检索它并将生成的响应对象添加到给定的缓存中。这在功能上等效于调用
fetch()
,然后使用put()
将结果添加到缓存中。 Cache.addAll()
-
获取 URL 数组,检索它们并将生成的响应对象添加到给定的缓存中。
Cache.put()
-
获取请求及其响应,并将其添加到给定的缓存中。
Cache.delete()
-
查找其键为请求的
Cache
条目,返回一个Promise
,如果找到并删除了匹配的Cache
条目,则该 Promise 解析为true
。如果未找到Cache
条目,则 Promise 解析为false
。 Cache.keys()
-
返回一个
Promise
,该 Promise 解析为Cache
键的数组。
示例
此代码片段来自Service Worker 选择性缓存示例。(参见选择性缓存实时)代码使用CacheStorage.open()
打开任何 Content-Type
标头以 font/
开头的 Cache
对象。
然后,代码使用Cache.match()
检查缓存中是否已经有匹配的字体,如果有,则返回它。如果没有匹配的字体,则代码从网络中获取字体并使用Cache.put()
缓存获取的资源。
代码处理从fetch()
操作抛出的异常。请注意,HTTP 错误响应(例如,404)不会触发异常。它将返回一个具有相应错误代码的普通响应对象。
代码片段还展示了 Service Worker 使用的缓存版本控制的最佳实践。尽管在此示例中只有一个缓存,但相同的方法可用于多个缓存。它将缓存的简写标识符映射到特定版本的缓存名称。代码还删除了 CURRENT_CACHES
中未命名的所有缓存。
在代码示例中,caches
是ServiceWorkerGlobalScope
的属性。它持有 CacheStorage
对象,通过它可以访问CacheStorage
接口。
注意:在 Chrome 中,访问 chrome://inspect/#service-workers
并单击注册的 Service Worker 下方的“检查”链接以查看service-worker.js
脚本正在执行的各种操作的日志语句。
const CACHE_VERSION = 1;
const CURRENT_CACHES = {
font: `font-cache-v${CACHE_VERSION}`,
};
self.addEventListener("activate", (event) => {
// Delete all caches that aren't named in CURRENT_CACHES.
// While there is only one cache in this example, the same logic
// will handle the case where there are multiple versioned caches.
const expectedCacheNamesSet = new Set(Object.values(CURRENT_CACHES));
event.waitUntil(
caches.keys().then((cacheNames) =>
Promise.all(
cacheNames.map((cacheName) => {
if (!expectedCacheNamesSet.has(cacheName)) {
// If this cache name isn't present in the set of
// "expected" cache names, then delete it.
console.log("Deleting out of date cache:", cacheName);
return caches.delete(cacheName);
}
}),
),
),
);
});
self.addEventListener("fetch", (event) => {
console.log("Handling fetch event for", event.request.url);
event.respondWith(
caches.open(CURRENT_CACHES.font).then((cache) => {
return cache
.match(event.request)
.then((response) => {
if (response) {
// If there is an entry in the cache for event.request,
// then response will be defined and we can just return it.
// Note that in this example, only font resources are cached.
console.log(" Found response in cache:", response);
return response;
}
// Otherwise, if there is no entry in the cache for event.request,
// response will be undefined, and we need to fetch() the resource.
console.log(
" No response for %s found in cache. About to fetch " +
"from network…",
event.request.url,
);
// We call .clone() on the request since we might use it
// in a call to cache.put() later on.
// Both fetch() and cache.put() "consume" the request,
// so we need to make a copy.
// (see https://mdn.org.cn/en-US/docs/Web/API/Request/clone)
return fetch(event.request.clone()).then((response) => {
console.log(
" Response for %s from network is: %O",
event.request.url,
response,
);
if (
response.status < 400 &&
response.headers.has("content-type") &&
response.headers.get("content-type").match(/^font\//i)
) {
// This avoids caching responses that we know are errors
// (i.e. HTTP status code of 4xx or 5xx).
// We also only want to cache responses that correspond
// to fonts, i.e. have a Content-Type response header that
// starts with "font/".
// Note that for opaque filtered responses
// https://fetch.spec.whatwg.org/#concept-filtered-response-opaque
// we can't access to the response headers, so this check will
// always fail and the font won't be cached.
// All of the Google Web Fonts are served from a domain that
// supports CORS, so that isn't an issue here.
// It is something to keep in mind if you're attempting
// to cache other resources from a cross-origin
// domain that doesn't support CORS, though!
console.log(" Caching the response to", event.request.url);
// We call .clone() on the response to save a copy of it
// to the cache. By doing so, we get to keep the original
// response object which we will return back to the controlled
// page.
// https://mdn.org.cn/en-US/docs/Web/API/Request/clone
cache.put(event.request, response.clone());
} else {
console.log(" Not caching the response to", event.request.url);
}
// Return the original response object, which will be used to
// fulfill the resource request.
return response;
});
})
.catch((error) => {
// This catch() will handle exceptions that arise from the match()
// or fetch() operations.
// Note that a HTTP error response (e.g. 404) will NOT trigger
// an exception.
// It will return a normal response object that has the appropriate
// error code set.
console.error(" Error in fetch handler:", error);
throw error;
});
}),
);
});
Cookie 和缓存对象
Fetch API 要求在从fetch()
返回Response
对象之前,先剥离Set-Cookie
标头。因此,存储在 Cache
中的 Response
不会包含 Set-Cookie
标头,因此不会导致存储任何 Cookie。
规范
规范 |
---|
Service Workers # cache-interface |
浏览器兼容性
BCD 表仅在启用 JavaScript 的浏览器中加载。