self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request)
.then(function(response) {
// Cache hit - return response
if (response) {
return response;
}
// IMPORTANT:Clone the request. A request is a stream and
// can only be consumed once. Since we are consuming this
// once by cache and once by the browser for fetch, we need
// to clone the response.
var fetchRequest = event.request.clone();
return fetch(fetchRequest).then(
function(response) {
// Check if we received a valid response
if(!response || response.status !== 200 || response.type !== 'basic') {
return response;
}
// IMPORTANT:Clone the response. A response is a stream
// and because we want the browser to consume the response
// as well as the cache consuming the response, we need
// to clone it so we have two streams.
var responseToCache = response.clone();
caches.open(CACHE_NAME)
.then(function(cache) {
cache.put(event.request, responseToCache);
});
return response;
}
);
})
);
});
无需验证
脚本长期不变,可以做设置文件返回Http头
虽然文件长期不变,但是标准推荐max-age最大不超过一年,以秒为单位的话就是 31536000
如果有修改,更新文件名即可
需要验证
一般文件都不会只请求一次,所以不会设置这个大的值,比如设置2分钟max-age=120
但是两分钟后脚本没有更新又完整下载文件也不合理,所以缓存有验证机制。即协商缓存。如果验证发现有更改,就返回完整内容(http状态码200);否则返回304 Not modified ,浏览器就可以继续使用缓存文件。
技术细节
no-cache
,no-store
,must-revalidate
Cache-Control
不仅可以设置max-age,还有很多其他只,以及可以组合Expires
VS.max-age
他们都是用于控制缓存的生命周期。
Expires是http/1.0的标准,过期的绝对时间,比较复杂(Sun, 21 Mar 2027 08:52:14 GMT),而且客户端时间和服务端时间不一致可能导致失效
max-age是http/1.1中的标准,是相对时间,设置简单
Etag
VS.Last-Modified
都可以用于对资源进行验证,一个是验证时间,一个是验证类似hash值得东西
Etag是强验证,它期望资源字节级别一致,更精确,优先级更高,再次请求资源时使用
If-None-Match
发送服务端Last-Modified属于弱验证,精度更低,只验证要秒的时间,如果资源可能在毫秒级的时间多次修改,那么设置这个缓存则没有意义。再次请求时使用
If-Modified-Since
或If-Unmodified-Since
max-age=0
VS.no-cache
max-age=0是在告诉浏览器,资源已经过期了,你应该(SHOULD)对资源进行重新验证了;而no-cache则是告诉浏览器在每一次使用缓存之前,你必须(MUST)对资源进行重新验证。
区别在于,SHOULD是非强制性的,而MUST是强制性的。在no-cache的情况下,浏览器在向服务器验证成功之前绝不会使用过期的缓存资源,而max-age=0则不一定了。虽然理论上来说它们的效果应该是一致的。
public
VS.private
主要是 Cache-Control 设置为 private 以避免中间服务器缓存。
不要对变化的资源添加较短的max-age
Service Worker 与缓存
它是一种 JavaScript Worker,无法直接访问 DOM。 Service Worker 通过响应 postMessage 接口发送的消息来与其控制的页面通信,页面可在必要时对 DOM 执行操作。
Service Worker 的生命周期完全独立于网页。
注册sw
安装 Service Worker
缓存和返回请求
在安装 Service Worker 且用户转至其他页面或刷新当前页面后,Service Worker 将开始接收 fetch 事件。下面提供了一个示例。
如果希望连续缓存新请求,可以通过处理 fetch 请求的响应并将其添加到缓存来实现,如下所示。
fetch
请求中添加对.then()
的回调。200
。浏览器的整体缓存机制
除了HTTP标准缓存以外,浏览器还有可能存在标准以外的缓存机制。对于Chrome浏览器而言还存在Memory Cache、Push “Cache”。一个请求在查找资源的过程中经过的缓存顺序是Memory Cache、Service Worker、HTTP Cache、Push “Cache”。HTTP Cache和Service Worker已经介绍过了,接下来简单介绍Memory Cache和Push Cache
Memory Cache
“内存缓存”中主要包含的是当前文档中页面中已经抓取到的资源。例如页面上已经下载的样式、脚本、图片等。我们不排除页面可能会对这些资源再次发出请求,所以这些资源都暂存在内存中,当用户结束浏览网页并且关闭网页时,内存缓存的资源会被释放掉。
这其中最重要的缓存资源其实是preloader相关指令(例如
<link rel="prefetch">
)下载的资源。总所周知preloader的相关指令已经是页面优化的常见手段之一,而通过这些指令下载的资源也都会暂存到内存中。根据一些材料,如果资源已经存在于缓存中,则可能不会再进行preload。需要注意的事情是,内存缓存在缓存资源时并不关心返回资源的HTTP缓存头Cache-Control是什么值,同时资源的匹配也并非仅仅是对URL做匹配,还可能会对Content-Type,CORS等其他特征做校验
Push “Cache”
“推送缓存”是针对HTTP/2标准下的推送资源设定的。推送缓存是session级别的,如果用户的session结束则资源被释放;即使URL相同但处于不同的session中也不会发生匹配。推送缓存的存储时间较短,在Chromium浏览器中只有5分钟左右,同时它也并非严格执行HTTP头中的缓存指令