浏览器缓存之http缓存和service worker

相关代码下载地址:https://download.csdn.net/download/u010674395/12555506

一、什么是浏览器缓存

以往谈起性能优化,大部分时候都是从后端聊起,数据库的设计,缓存的使用等。其实前端在性能优化方面可做的也很多,如:减少http请求数、使用cdn、压缩合并css/js等,浏览器缓存就是把已经请求过的Web资源进行存储,当用户刷新页面或者下次访问时候,浏览器根据缓存机制决定是否需要向服务端发起请求。 所以缓存可以带来:减少网络带宽消耗、降低服务器压力、减少网络延迟,加快页面打开速度等优点

二、浏览器缓存有哪些

1、http缓存是基于HTTP协议的浏览器文件级缓存机制。

2、websql这种方式只有较新的chrome浏览器支持,并以一个独立规范形式出现

3、indexDB 是一个为了能够在客户端存储可观数量的结构化数据,并且在这些数据上使用索引进行高性能检索的 API

4、Cookie一般网站为了辨别用户身份、进行session跟踪而储存在用户本地终端上的数据(通常经过加密)

5、Localstorage是html5的一种新的本地缓存方案,目前用的比较多,一般用来存储ajax返回的数据,加快下次页面打开时的渲染速度

6、Sessionstorage和localstorage类似,但是浏览器关闭则会全部删除,api和localstorage相同,实际项目中使用较少。

7、application cache 是将大部分图片资源、js、css等静态资源放在manifest文件配置中

8、cacheStorage是在ServiceWorker的规范中定义的,可以保存每个serverWorker申明的cache对象 今天重点说下http缓存和serviceworker

三、浏览器缓存存放的位置

浏览器缓存之http缓存和service worker_第1张图片

通过上图可发现: 浏览器缓存有一些资源存在了memory cache(内存中) 有一些资源存在了disk cache(磁盘中) 关掉页面再重新请求,会是什么样?(自己实践一下)

1、memory cache

按照操作系统的常理:先读内存,再读硬盘。几乎所有的网络请求资源都会被浏览器自动加入到 memory cache 中。但是也正因为数量很大但是浏览器占用的内存不能无限扩大这样两个因素,memory cache 注定只能是个“短期存储”。常规情况下,浏览器的 TAB 关闭后该次浏览的 memory cache 便告失效 (为了给其他 TAB 腾出位置)。而如果极端情况下 (例如一个页面的缓存就占用了超级多的内存),那可能在 TAB 没关闭之前,排在前面的缓存就已经失效了。 memory cache 机制保证了一个页面中如果有两个相同的请求 (例如两个 src 相同的 ,两个 href 相同的 )都实际只会被请求最多一次,避免浪费。 在从 memory cache 获取缓存内容时,浏览器会忽视例如 max-age=0, no-cache 等头部配置。 如果站长是真心不想让一个资源进入缓存,就连短期也不行,那就需要使用 no-store。 思考:刚才提到 几乎所有的网络请求资源都会被浏览器自动加入到 memory cache 中,为什么? preloader,在2007年之前,许多情况下,浏览器某些元素的解析和执行可能会影响紧随其后的资源,浏览器停止并等待资源完成下载,然后再获取下一个资源。这意味着如果一个页面包含多个JavaScript资源或外部CSS资源,在它们之后的元素,解析器将暂停并等待每个外部资源完成下载,然后再获取下一行内容。随着页面越来越繁琐的JavaScript,对性能的影响是巨大的,并且是灾难性的。所以在资源解析执行时候,网络状态是空闲的,能不能边解边请求资源呢,在2008年,ie/谷歌等浏览器便有了相关的机制(预加载器机制),预加载的资源都是放在memory cache中的。

2、disk cache

存储在硬盘上的缓存会严格根据 HTTP 头信息中的各类字段来判定哪些资源可以缓存,哪些资源不可以缓存;哪些资源是仍然可用的,哪些资源是过时需要重新请求的。当命中缓存之后,浏览器会从硬盘中读取资源,虽然比起从内存中读取慢了一些,但比起网络请求还是快了不少的。绝大部分的缓存都来自 disk cache。 凡是持久性存储都会面临容量增长的问题,disk cache 也不例外。在浏览器自动清理时,每个浏览器都会识别“最老的”和“最可能过时的”资源。 HTTP 的协议头中的缓存字段,我们稍后再说

3、Service Worker

Service Worker 是 Chrome 团队提出和力推的一个 WEB API,用于给 web 应用提供高级的可持续的后台处理能力。 service worker 能够操作的缓存是有别于浏览器内部的 memory cache 或者 disk cache。它是独立于当前页面的一段运行在浏览器后台进程里的脚本。大家可以把 Service Worker 理解为一个介于客户端和服务器之间的一个代理服务器。在 Service Worker 中我们可以做很多事情,比如拦截客户端的请求、向客户端发送消息、向服务器发起请求等等,离线资源缓存只是它的作用之一。 这个缓存是永久性的,即关闭 TAB 或者浏览器,下次打开依然还在(而 memory cache 不是)。有两种情况会导致这个缓存中的资源被清除:手动调用 API cache.delete(resource) 或者容量超过限制,被浏览器全部清空。 Service Worker 特点 网站必须使用 HTTPS。除了使用本地开发环境调试时(如域名使用 localhost) 运行于浏览器后台,可以控制打开的作用域范围下所有的页面请求 单独的作用域范围,单独的运行环境和执行线程 不能操作页面 DOM。但可以通过事件机制来处理

4、Service Worker的注册和安装

if('serviceWorker' in navigator) {
    console.log('支持')
    window.navigator.serviceWorker
      .register('/sw.js', {
        scope: '/' // 作用域
      })
      .then(registration => {
        console.log('注册成功', registration.update)  
      })
      .catch(error => {
        console.log('注册失败', error.message)
      })
  } else {
    console.log('不支持')
  }


self.addEventListener('install', event => {
    // event.waitUtil 用于在安装成功之前执行一些预装逻辑
    // 建议只做一些非常重要资源的缓存,减少安装失败的概率
    // 安装成功后 ServiceWorker 状态会从 installing 变installed
    event.waitUntil(
        // 使用 cache API 打开指定的 cache 文件
        caches.open('版本标识').then(cache => {
            console.log(cache);
            // 添加要缓存的资源列表
            return cache.addAll('要缓存的文件列表');
        })
    );
});

四、强制缓存

强制缓存的含义是,当客户端请求后,会先访问缓存数据库看缓存是否存在。如果存在则直接返回;不存在则请求真的服务器,响应后再写入缓存数据库。 强制缓存直接减少请求数,是提升最大的缓存策略。如果考虑使用缓存来优化网页性能的话,强制缓存应该是首先被考虑的。 可以造成强制缓存的字段是 Cache-control 和 Expires。 Expires是http1.0的字段,表示缓存到期时间,是一个绝对的时间。在响应消息头中,设置这个字段之后,就可以告诉浏览器,在未过期之前不需要再次请求。 缺点:用户更改客户端时间就会造成失效。时间字符串多个空格等都会报错(Expires: Thu, 10 Nov 2020 08:45:11 GMT) Cache-control是HTTP/1.1的字段,该字段表示资源缓存的最大有效时间,在该时间内,客户端不需要向服务器发送请求。 这两者的区别就是前者是绝对时间,而后者是相对时间。 Cache-control 的优先级高于 Expires,为了兼容 HTTP/1.0 和 HTTP/1.1,实际项目中两个字段可以都设置。

1、强制缓存之Cache-control的值

max-age:即最大有效时间

must-revalidate:如果超过了 max-age 的时间,浏览器必须向服务器发送请求,验证资源是否还有效。

no-cache:虽然字面意思是“不要缓存”,但实际上还是要求客户端缓存内容的,只是是否使用这个内容由后续的对比来决定。

no-store: 真正意义上的“不要缓存”。所有内容都不走缓存,包括强制和对比。

public:所有的内容都可以被缓存 (包括客户端和代理服务器, 如 CDN)

private:所有的内容只有客户端才可以缓存,代理服务器不能缓存。默认值。

五、对比缓存 (协商缓存)

当强制缓存失效(超过规定时间)时,就需要使用对比缓存,由服务器决定缓存内容是否失效。

流程上说,浏览器先请求缓存数据库,返回一个缓存标识。之后浏览器拿这个标识和服务器通讯。如果缓存未失效,则返回 HTTP 状态码 304 表示继续使用,于是客户端继续使用缓存;如果失效,则返回新的数据和缓存规则,浏览器响应数据后,再把规则写入到缓存数据库。 对比缓存在请求数上和没有缓存是一致的,但如果是 304 的话,返回的仅仅是一个状态码而已,并没有实际的文件内容,因此 在响应体体积上的节省是它的优化点。它的优化体现在浏览器的“响应”上。通过减少响应体体积,来缩短网络传输时间。所以和强制缓存相比提升幅度较小,但总比没有缓存好。

对比缓存是可以和强制缓存一起使用的,作为在强制缓存失效后的一种后备方案。实际项目中他们也的确经常一同出现。

服务器通过 Last-Modified 字段告知客户端,资源最后一次被修改的时间,例如

Last-Modified: Mon, 10 Nov 2020 09:10:11 GMT

浏览器将这个值和内容一起记录在缓存数据库中。

下一次请求相同资源时时,浏览器从自己的缓存中找出“不确定是否过期的”缓存。因此在请求头中将上次的 Last-Modified 的值写入到请求头的 If-Modified-Since 字段 服务器会将 If-Modified-Since 的值与 Last-Modified 字段进行对比。如果相等,则表示未修改,响应 304;反之,则表示修改了,响应 200 状态码,并返回数据。

但是他还是有一定缺陷的: 如果资源更新的速度是秒以下单位,那么该缓存是不能被使用的,因为它的时间单位最低是秒。 如果文件是通过服务器动态生成的,那么该方法的更新时间永远是生成的时间,尽管文件可能没有变化,所以起不到缓存的作用。

为了解决上述问题,出现了一组新的字段 Etag 和 If-None-Match Etag 存储的是文件的特殊标识(一般都是 hash 生成的),服务器存储着文件的 Etag 字段。之后的流程和 Last-Modified 一致,只是 Last-Modified 字段和它所表示的更新时间改变成了 Etag 字段和它所表示的文件 hash,把 If-Modified-Since 变成了 If-None-Match。服务器同样进行比较,命中返回 304, 不命中返回新资源和 200。

Etag 的优先级高于 Last-Modified

浏览器缓存之http缓存和service worker_第2张图片

六、缓存小结

当浏览器要请求资源时 调用 Service Worker 的 fetch 事件响应 查看 memory cache 查看 disk cache。这里又细分:     如果有强制缓存且未失效,则使用强制缓存,不请求服务器。这时的状态码全部是 200     如果有强制缓存但已失效,使用对比缓存,比较后确定 304 还是 200 发送网络请求,等待网络响应 把响应内容存入 disk cache (如果 HTTP 头信息配置可以存的话) 把响应内容 的引用 存入 memory cache (无视 HTTP 头信息的配置) 把响应内容存入 Service Worker 的 Cache Storage (如果 Service Worker 的脚本调用了 cache.put())

你可能感兴趣的:(js)