缓存知识适合所有js html css img等
是否已经存在于用户的缓存中,得知有哪些缓存,顺序是什么
浏览器寻找的以次顺序是:
1.内存缓存
2.Service Worker缓存
3.HTTP 缓存
4.HTTP/2 push 缓存
内存缓存
但是像“短期内存缓存”这样的名称可能更合适:内存缓存仅在导航结束之前保留资源,在某些情况下,甚至更少。
(link rel=preload)是预加载资源存储在内存缓存中的另一大案例。
但是,内存缓存不会轻易地为请求提供匹配的资源。显然,为了使请求和资源匹配,它们必须具有匹配的URL。但是,这还不够。它们还必须具有匹配的资源类型(因此作为脚本提取的资源不能与图像请求匹配),CORS模式和一些其他特征。
来自内存缓存的请求的匹配特性在规范中没有明确定义,因此可能在浏览器实现之间略有不同。
Memory Cache不关心的一件事是HTTP语义。如果存储在其中的资源具有max-age=0或no-cache Cache-Control标头,那么这不是Memory Cache所关心的。由于它允许在当前导航中重用资源,因此HTTP语义在这里并不重要。
Service Worker缓存
缓存是持久的,比memory cache生命周期长 。
从某种程度上说,它是不可预测的,只能遵守他们的主人,Web开发人员告诉他们的内容。
首先,只有在页面安装了Service Worker时才存在。由于它的逻辑是由Web开发人员使用JavaScript定义的,而不是内置到浏览器中。
Service Worker具有缓存API,使其能够保留资源。它与Memory Cache之间的一个主要区别在于它是持久的。
需要额外写Service Worker的代码。缓存不会失效,除非开发人员写的代码明确删除。
如果浏览器的存储空间不足,则会出现另一种情况,在这种情况下, 整个 Service Worker缓存以及所有其他原始存储(例如indexedDB,localStorage等)都会被破坏。这样,Service Worker就可以知道该缓存中的资源在它们之间以及与其他原始存储器同步。
服务工作者负责某个范围,最多只限于一个主机。因此,服务工作者只能响应对该范围内文档请求的请求。
Service worker 缓存的好处是可以不需要服务端配合,但是service work必定no-store。
思考:Service Worker可以更复杂和细粒度的控制缓存以编程的形式。所以manifest cache就被淘汰了,相比之下两者都能达到相同的功能但Service Worker灵活度更高。
example:
const version = '2';
self.addEventListener('install', event => {
event.waitUntil(
caches.open(`static-${version}`)
.then(cache => cache.addAll([
'/styles.css',
'/script.js'
]))
);
});
self.addEventListener('activate', event => {
// …delete old caches…
});
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request)
.then(response => response || fetch(event.request))
);
});
扩展阅读caching best practices
服务工作者最好是作为一种增强而不是解决方法,所以不要使用缓存,而是使用它!
HTTP 缓存
HTTP缓存通过HTTP Header来描述缓存逻辑。
强缓存
实现强缓存可以通过两种响应头实现:Expires 和 Cache-Control。强缓存表示在缓存期间不需要请求,state code为200。
Expires 是 HTTP / 1.0 的产物,表示资源会在 Wed, 22 Oct 2018 08:41:00 GMT 后过期,需要再次请求。并且 Expires 受限于本地时间,如果修改了本地时间,可能会造成缓存失效。
Expires: Wed, 22 Oct 2018 08:41:00 GMT
Cache-Control 出现于 HTTP / 1.1,优先级高于 Expires 。该属性表示资源会在 30 秒后过期,需要再次请求。
Cache-Control: max-age=30
优先使用Cache-Control, Cache-Control部分字段解释:
- max-age=
该属性表示资源会在seconds秒后过期,需要再次请求。 - no-store 缓存不应存储有关客户端请求或服务器响应的任何内容。如果是Service Worker缓存的,建议使用。
- no-cache 表示必须先与服务器确认返回的响应是否发生了变化,然后才能使用该响应来满足后续对同一网址的请求。因此,如果存在合适的验证令牌 (ETag),no-cache 会发起往返通信来验证缓存的响应(例如If-None-Match或If-Modified-Since),但如果资源未发生变化,则可避免下载。
- immutable 表示响应正文不会随时间变化。资源(如果未过期)在服务器上未更改,因此客户端不应为其发送条件重新验证(例如If-None-Match或If-Modified-Since)以检查更新,即使用户明确刷新页面也是如此。通常在https中实现。
- public 表示任何缓存都可以缓存响应。即使它有关联的HTTP身份验证,甚至响应状态代码通常是无法缓存,最终也可以缓存响应。大多数情况下,“public”不是必需的,因为明确的缓存信息(例如“max-age”)已表示响应是可以缓存的。
- private 浏览器可以缓存“private”响应。不过,这些响应通常只为单个用户缓存,因此不允许任何中间缓存对其进行缓存。例如,用户的浏览器可以缓存包含用户私人信息的 HTML 网页,但 CDN 却不能缓存。
immutable的推荐用法是和那些超大的 max-age 配合使用,比如 1年:Cache-Control: max-age=31536000, immutable,甚至 10年, 但通常情况下,1 年就够了,因为:1. 对于单个缓存来说,它在某个浏览器里存活的时长不可能超过一年,浏览器的缓存空间都有上限,Firefox 256M,Chrome 320M,旧的缓存会时不时被清掉。
immutable并不是真的只能应用在那些永不过期的资源上,也可以配合较小的 max-age 来使用,比如一些个人博客,或者一些不太讲究及时更新的站点,可以设置成 Cache-Control: max-age=3600, immutable,表明该资源能存活一小时,在一小时之内,即便用户刷新也不要发送条件请求。这里需要注意,一旦被标志成 immutable,则这个资源不可能返回 304 响应了,只有 200。
Cache-Control参考链接
协商缓存
协商缓存,如果缓存过期了,我们就可以使用协商缓存来解决问题。协商缓存需要请求,如果缓存有效会返回 304。
协商缓存需要客户端和服务端共同实现,和强缓存一样,也有两种实现方式。
- Last-Modified和If-Modified-Since。Last-Modified表示文件最后修改日期。If-Modified-Since会将Last-Modified的值发送给服务器,询问是否有更新,有更新则将新资源发送回来。如果本地打开缓存文件,就会造成Last-Modified被修改
- ETag和If-None-Match。If-None-Match会将当前ETag(相当于指纹)发送给服务器,询问是否变动,如果有就发送新资源发送回来。ETag优先级大于Last-Modified。
注意 在任何资源上禁止头部 Last-Modified 都会导致一个 If-Modified-Since 条件查询,即使资源在缓存中。与 Etag 一样,即使它在使用中。
缓存策略
- 对于某些不需要缓存的资源,可以使用 Cache-control: no-store ,表示该资源不需要缓存。
- 对于频繁变动的资源,可以使用 Cache-Control: no-cache 并配合 ETag 使用,表示该资源已被缓存,但是每次都会发送请求询问资源是否更新。
- 对于代码文件来说,通常使用 Cache-Control: max-age=31536000 并配合策略缓存使用,然后对文件进行指纹处理,一旦文件名变动就会立刻下载新的文件。如style.x234diff.css
如果多个页面,都使用相同的资源,我们可以相同的域名和文件名使其达到共享缓存的作用。
缓存检查清单
不存在什么最佳缓存策略。您需要根据通信模式、提供的数据类型以及应用特定的数据更新要求,为每个资源定义和配置合适的设置,以及整体的“缓存层次结构”。
在制定缓存策略时,您需要牢记下面这些技巧和方法:
- 使用一致的网址:如果您在不同的网址上提供相同的内容,将会多次获取和存储这些内容。提示:请注意,网址区分大小写。
- 确保服务器提供验证令牌 (ETag):有了验证令牌,当服务器上的资源未发生变化时,就不需要传送相同的字节。
- 确定中间缓存可以缓存哪些资源:对所有用户的响应完全相同的资源非常适合由 CDN 以及其他中间缓存进行缓存。
- 为每个资源确定最佳缓存周期:不同的资源可能有不同的更新要求。为每个资源审核并确定合适的 max-age。
- 确定最适合您的网站的缓存层次结构:您可以通过为 HTML 文档组合使用包含内容指纹的资源网址和短时间或 no-cache 周期,来控制客户端获取更新的速度。
- 最大限度减少搅动:某些资源的更新比其他资源频繁。如果资源的特定部分(例如 JavaScript 函数或 CSS 样式集)会经常更新,可以考虑将其代码作为单独的文件提供。这样一来,每次获取更新时,其余内容(例如变化不是很频繁的内容库代码)可以从缓存获取,从而最大限度减少下载的内容大小。
扩展阅读Heroku的HTTP缓存头部
比如Vue Cli3的创建的模板项目中的web server就提供了上述缓存功能,尤其是生出的dist目录下的文件都带了指纹(app.06f96ef0.js)。
HTTP/2 Push缓存
Push缓存(更好地描述为“无人认领的推送流容器”,但名称不那么吸引人)是存储HTTP / 2推送资源的地方。它们存储为HTTP / 2会话的一部分,具有多种含义。
容器没有持久性。如果会话终止,则所有未声明的资源(即与其请求不匹配)都将消失。如果使用不同的HTTP / 2会话获取资源,则不会匹配。最重要的是,资源仅在有限的时间内保留在推送缓存容器中。(在基于Chromium的浏览器中约5分钟)
Push缓存根据其URL以及其各种请求标头匹配对资源的请求,但它不应用严格的HTTP语义。
Push缓存在规范中也没有明确定义,并且实现可能因浏览器,操作系统和其他HTTP / 2客户端而异。
由于可以在多个选项卡之间重复使用 HTTP/2 连接,所以推送的资源也可以被来自其他选项卡的请求声明.
目前,服务器并没有一个简单的方法得知被推送的资源 是否已经存在于用户的缓存中,因此每个用户的访问都会继续推送资源。因此,您可能需要创建一个缓存监测 HTTP/2 服务器推送机制(通过服务器加cookie来确定)。如果被提取,您可以尝试从缓存中获取它们,这样可以避免再次推送。但请记住,新的cache-digest规范无需手动建立这样的 “缓存感知” 的服务器
介绍:cache-digest 缓存摘要
Cache Digest是IETF HTTP工作组目前正在讨论的规范。11请注意,规范正在进行更改,如果它完全通过标准轨道,那么您在此处阅读的内容可能无法反映最终标准。客户端将缓存摘要发送到服务器。它告诉服务器客户端的缓存包含什么。知道哪些资产已经或者没有被客户端缓存的服务器可以准确地推送所需的内容。
最后,可以想象以下情况,某些资源客户端是一定会请求的,这时就可以采取服务端 push 的技术,提前给客户端推送必要的资源,这样就可以相对减少一点延迟时间。当然在浏览器兼容的情况下你也可以使用preload/prefetch。扩展阅读http2-push-vs-http-preload
是否要使用push cashe呢,可以参考Should I Push。
思考:目前看起来使用Push缓存难度有点大,性价比不高。