浏览器缓存,HTTP缓存,service work缓存详解

44 阅读5分钟

缓存是提高受屏渲染速度,用户交互体验中非常重要的一环,合理的利用缓存,可以使网页性能更加流畅。首先缓存大致有三种,浏览器缓存,HTTP缓存,service work缓存。

浏览器缓存

浏览器缓存是最常见的一种,也就是我们熟知的sessionStorage和localStorage

session缓存

session缓存常用于保存账号信息,或组件间传递数据等,可以设置其过期事件,或随着浏览器或当前会话窗口的关闭,一同删除,并且其内部信息只能在当前窗口内能够访问到,本质上来说,其内部信息储存在内存中,是临时缓存,而不能长久保存。

local缓存

local缓存也可以用于保存数据,但要注意数据是否需要长久保存,且local的作用域并非当前窗口,而是浏览器中所有的同域名窗口都能获取,所以使用时需要注意两者的区别,针对需求选择使用。由于local缓存能够长久保存数据(本质是保存在硬盘中),所以合理的使用local缓存也能实现提升首屏渲染速度的需求。

HTTP缓存

HTTP缓存分为强缓存和协商缓存

强缓存

强缓存是在HTTP响应头中保存固定时间段( Cache-Control: max-age=3600 单位秒)或指定过期时间点( Expires),来实现绝对时间的期限,所以当两个缓存都被设置在响应头中时(缓存的开启需要后端返回数据时,在响应头中添加一些属性,后面说),强缓存会被优先检测,因为强缓存不需要和服务器交互,只需要判断检查自身,就可以知道资源是否过期。

协商缓存

一旦强缓存没有命中,或者强缓存被禁用( Cache-Control: no-cache),那么就会开启协商缓存检测,协商缓存是后端在表头中添加固定标识( ETag)或者资源修改时间( Last-Modified),在第二次请求该资源时,浏览器会和服务器对比标识或修改资源时间,如果确定资源未修改过,则使用缓存资源,反之重新请求。

相关的响应头

Cache-Control:

  • no-cache: 表示禁用强制缓存,直接使用协商缓存,如果没有协商缓存,则直接请求新数据。
  • no-store: 表示不缓存任何资源,每次请求都需要从服务器获取完整的资源。
  • public: 表示响应可以被任何中间缓存(例如代理服务器)缓存。
  • private: 表示响应仅能被终端用户的浏览器缓存,不允许中间缓存。
  • max-age=3600(单位秒)

**Expires:**设置绝对过期时间(例如:Wed, 21 Jul 2022 07:00:00 GMT)

ETag: ETag 是一个由服务器生成的资源唯一标识符,用于协商缓存。可设置的值是任何字符串,通常是资源的哈希值或版本号。

Last-Modified: Last-Modified 表示资源的最后修改时间,用于协商缓存。可设置的值是一个 GMT 格式的日期字符串(例如:Wed, 21 Jul 2021 07:00:00 GMT)。

HTTP缓存的单元是一个url,也就是说可以是一个图片的链接,也可以是一个后端的接口,总之就是一个url,在url返回HTTP包,并且,响应头有缓存标识,那么这个资源就会被缓存起来,在第二次向这个url发送请求时,则会检查缓存资源,强缓存或协商缓存,HTTP缓存无需代码干涉,只需要后端对响应头进行对应设置即可自动缓存在客户端。

service worker缓存

Service Worker 是一种在浏览器后台运行的脚本,它可以拦截和处理网页发起的网络请求,提供离线缓存和推送通知等功能。在离线缓存方面,Service Worker 可以使用 Cache API 来创建自定义的缓存,进而实现对资源的离线存储和提供离线访问。

service worker缓存可以通过自行编程的方式来控制缓存规则,更加自由。基本流程如下

通过调用 navigator.serviceWorker.register() 方法注册 Service Worker

if ('serviceWorker' in navigator) {//查看浏览器是否支持serviceWorker
  navigator.serviceWorker.register('/service-worker.js')//将一个js文件注册为serviceWorker
    //监听是否注册成功
    .then(registration => {
      console.log('Service Worker registered with scope:', registration.scope);
    })
    .catch(error => {
      console.error('Error registering Service Worker:', error);
    });
}

创建一个 Service Worker 文件(也就是上面注册的 service-worker.js文件),在这个文件中可以监听 install、activate、fetch 等生命周期事件。

const CACHE_NAME = 'my-cache-v1';//定义缓存区名字

self.addEventListener('install', event => {//监听初始化时间
  event.waitUntil(
    caches.open(CACHE_NAME).then(cache => {//在浏览器缓存中开启一个名为my-cache-v1的缓存区用来
                                           //缓存资源
      return cache.addAll([
        '/',
        '/index.html',
        '/styles.css',
        '/script.js',
        // Add other resources to be cached
      ]);
    })
  );
});

fetch是缓存网络请求资源,activate是发生在install后的一个事件,常用于清理旧缓存,这里就不细说了

一个域名创建出来的缓存区默认也是这个域名,从缓存区获取资源也受同源策略影响(可以使用跨域资源共享CORS,或共享缓存标识符方式实现跨域)。所以一个域名正常条件下只能获取自己创建的缓存区,也正是因为这样,两个会话之间也不会因为创建缓存区而出现命名冲突。