前端浏览器缓存机制 您所在的位置:网站首页 浏览器缓存刷新 前端浏览器缓存机制

前端浏览器缓存机制

2023-05-30 16:33| 来源: 网络整理| 查看: 265

前言

最近在做一个第三方平台跳转登陆的需求,由该需求可以发散到对应的知识有:浏览器缓存、单点登录等。为此我也想到了一个接下来让自己去适应的学习计划,那就是基于当前工作中项目需求里需要用到的知识去扩展学习,以此类推,下个需求又有哪些知识点,再去学习那方面相关的知识。至于学习的深度、拓展到多少相关知识点,则由该段时间自由度来决定。

缓存

缓存: 一般指的都是静态资源文件的缓存,这个一般是客户端和服务器端根据一些协商的规则,自动去完成的缓存策略(不用我们自己编写啥代码去处理)。只有API接口数据缓存,是需要前端开发自己去完成的

1.为什么我们需要浏览器缓存?

当我们访问同一个页面时,请求资源、数据都是需要一定的耗时,如果可以将一些资源缓存下来,那么从第二次访问开始,就可以减少加载时间,提高用户体验,也能减轻服务器的压力。

2.缓存的分类

Web 缓存大致可以分为:数据库缓存、服务器端缓存(代理服务器缓存、CDN 缓存)、浏览器缓存。而浏览器缓存也包含了很多内容: HTTP 缓存(强缓存和协商缓存)、数据缓存(cookie、localstorage、indexDB...) 等。

3.缓存的位置

若设置了缓存机制,则从服务器获取的信息会存储在:

虚拟内存(内存条):Memory Cache(一般用于页面没有关闭,只是刷新) 物理内存(硬盘): Disk Cache(页面关闭后重新打开) 换而言之,客户端/浏览器会将缓存放在内存中一份,放在硬盘中一份。内存中的缓存,页面一关闭存储的信息就被释放了;硬盘中的缓存,是持久存储,页面关闭还有,除非自己使用一些手段清除掉,如 360清除浏览器缓存。

image.png

具体处理步骤:

打开网页:先读 Memory Cache,再读 Disk Cache。 页面关闭再打开:查找 disk cache 中是否有匹配,如有则使用,没有则发送网络请求。 普通刷新 (F5):TAB没关闭,因此 memory cache 是可用的,会被优先使用,其次才是 disk cache 强制刷新 (Ctrl + F5):浏览器不使用缓存,直接从服务器获取最新资源,因此发送的请求头部均带有 Cache-control: no-cache

4.缓存处理

检测缓存 ——> 先看是否存在强缓存(强缓存存在走强缓存)——> 强缓存不存在,再看是否有协商缓存(协商存在,还是走缓存)——> 协商也不存在,则直接从服务器获取最新内容 ——> 缓存起来...(依此类推)

5.缓存的优缺点

优点:

减少了不必要的数据传输,节省带宽 减少服务器的负担,提升网站性能 加快了客户端加载网页的速度 用户体验友好 缺点: 资源如果有更改但是客户端不及时更新会造成用户获取信息滞后,如果老版本有bug的话,情况会更加糟糕。 HTTP缓存

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

强缓存

1.强缓存的概念和流程

强缓存(又叫强制缓存)整体流程比较简单,就是在第一次访问服务器取到数据之后,在过期时间之内不会再去重复请求。实现这个过程的核心就是如何知道当前时间是否超过了过期时间,强缓存的过期时间通过第一次访问服务器时返回的响应头获取。在 http1.0 和 http1.1 版本中通过不同的响应头字段实现。

浏览器对于强缓存的处理:根据第一次请求资源时返回的响应头来确定的

Expires:缓存过期时间,用来指定资源到期的时间(HTTP/1.0) Cache-Control:cache-control: max-age=2592000第一次拿到资源后的2592000秒内(30天),再次发送请求,读取缓存中的信息(HTTP/1.1) 两者同时存在的话,Cache-Control优先级高于Expires

image.png

Cache-Control的一些属性:

no-cache :可以在本地缓存,可以在代理服务器缓存,需要先验证才可使用缓存 no-store : 禁止浏览器缓存,只能通过服务器获取 max-age : 设置资源的过期时间(效果与expires一样)

一般而言,在项目中是两种都设置

image.png

无论资源信息是从强缓存中获取,还是从服务器重新获取,HTTP状态码都是以200为主。

强缓存不适合于静态页面的缓存,如果页面都缓存了,以后服务器更新了产品,我们访问也是走的缓存数据,这样看不到最新的内容了。

2.强缓存模式下,其他资源信息的缓存和部署以及更新

问题:本地缓存了文件,但是服务器对应的资源文件更新了,我们如何保证获取的是最新的内容

请求资源文件「例如CSS/JS/图片...」的时候设置时间戳 基于webpack生成不同的资源名称(eg: xxx.min.css。若代码更新重新打包生成的资源名称就会改变) 「HASH戳」

第一次请求:

复制代码

过了一天 css/js内容改变了,再次发请求,保证时间戳不一样,这样就不会走本地强缓存了,而是重新从服务器拉取最新的资源。

复制代码

发现后缀和上次缓存的不一样,则重新拉取最新的信息。

HTML文件永远不会去做强缓存!否则无法保证服务器资源更新,客户端可以随时获取最新的信息。

平时项目中,除了静态页面以外,对于CSS/JS/图片一般都会做强缓存。

协商缓存

1.协商缓存的概念

协商缓存(也叫对比缓存)就是强缓存失效(或者不存在)(eg:html可以做协商缓存)后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程

静态页面可以使用协商缓存处理 对于其余的资源文件,我们使用 强缓存+协商缓存

2.协商缓存的两组字段

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

Etag & If-None-Match:前者是只要服务器资源文件改变就会生成一个不同的标识(一般都是 hash 生成的)。后者和上一组字段的 If-Modified-Since 的情况相似。服务端同样会将二者进行比较,命中返回 304, 不命中返回新资源和 200。

image.png

两者可以一起使用,ETag优先级更高。

image.png

刷新页面的问题:

F5刷新:不使用强缓存,使用协商缓存 ctrl+F5:二者都不使用

HTTP1.1中Etag的出现,主要是为了解决几个last-modified比较难解决的问题:

一些文件也许会周期性的更改,但其内容并不改变(仅仅改变的修改时间),这个时候我们并不希望客户端认为这个文件被修改了,而重新get。 某些文件修改非常频繁,比如在秒以下的时间内进行修改(如1s内修改了N次),if-modified-since 能检查到的粒度是秒级的,这种修改无法判断(或者说UNIX记录MTIME只能精确到秒)。 某些服务器不能精确的得到文件的最后修改时间。

共同点总结:

强缓存和协商缓存都是服务端设置,客户端浏览器自动执行,无须前端编写代码,而且都是对静态资源文件的处理。

数据缓存

数据缓存就是把不需要经常更新的数据接口,做缓存处理。数据缓存就不能依托服务器和浏览器来自动处理了,它需要JS存储方案以及相关的操作去编码实现。

1.数据缓存的需求

本地没有缓存数据/缓存失效,我们从服务器拉取最新数据(类似于强缓存);本地有缓存数据且未过期,我们直接读取缓存的数据(减少和服务器之间的交互频率,降低服务器压力,也可以提高页面的渲染速度...)

页面不刷新,我们某些内容频繁操作,但是数据不是需要实时获取最新的,则可以做一下缓存;只要页面刷新,重新从服务器获取数据; 页面只要不关闭,我们读取缓存数据「针对于不经常更新的数据」; 页面即使关闭,重新打开,我们也可以读取缓存中的数据「数据更新的频率更低,我们自己设定过期周期」; ...

2.客户端存储数据的方案

(全局)变量存储「vuex/redux」:页面刷新或者关闭后重新打开,之前存储的数据都没有了(内存释放问题导致的)

本地存储:即基于JS管理的本地存储方案(都是以明文形式存储,所以重要的信息尽可能不要直接存储,可以采取md5加密)

cookie

webStorage:localStorage & sessionStorage

IndexedDB

Web SQL

Cache

Manifest 离线存储

...

存储到本地的信息都是以字符串形式存储的!

基于JS管理的本地存储方案,都是存储到计算机物理内存中的,全局变量存储是存储在虚拟内存中的。

image.png

3.cookie

操作:通过 document.cookie 实现获取和设置

image.png

特点:

具备有效期:cookie是需要设置过期时间的,超过时间就失效了(在有效期内,不论页面是刷新还是关闭后再重新打开,存储的信息都在),并且有路径等限制! 受“源”和“浏览器”限制:cookie信息只允许同源访问,而且更换浏览器后也无法获取 存储大小有限制:同源下最多只允许存储4KB内容。 具有不稳定性:基于安全卫士或者浏览器自带的清除操作,会把cookie干掉;开启无痕浏览或者隐私模式,则不能存储cookie信息! 兼容性:cookie兼容低版本浏览器。 和服务器之间有“猫腻”:cookie并不算严格的本地存储,和服务器之间有很多的“猫腻”。客户端向服务器发送请求的时候,会默认把本地的cookie信息,基于请求头发送给服务器;并且如果服务器返回的响应头中有Set-Cookie字段,浏览器也会默认把这些信息在客户端本地种上cookie...!(因此本地cookie存储的越多,每一次向服务器发送请求传送的东西也越多,速度也越慢)

4.localStorage

操作:

localStorage.setItem(key,value) localStorage.getItem(key) localStorage.removeItem(key) localStorage.clear() // 清除所有... 复制代码

特点:

持久化本地存储:没有过期时间,页面关闭存储的内容也是在的,只有手动清除(或者卸载浏览器)才会清除 受“源”和“浏览器”限制 存储大小有限制:同源下最多只允许存储5M内容。 具有稳定性:清楚电脑垃圾或历史记录对其存储的信息没有影响,而且无痕模式下也可以存储信息! 和服务器之间毫无关联:除非自己手动将本地的存储信息传递给服务端,否则和服务器没有关系。

实现具备有效期的localStorage

存储信息的时候,多存储一个关于时间的键值对。 后期获取的时候,利用当前时间 - 存储时间来验证差值是否在你规定的有效期内。

后面会封装这块的代码实现。

5.sessionStorage

和 localStorage 只有一个区别:localStorage 是持久化存储,页面刷新或关闭,存储的信息还在;sessionStorage 是会话存储,页面刷新存储的信息还在,但页面一旦关闭(会话结束),存储的信息都会被释放。

6.封装 localStorage 实现数据缓存的方法

/** * 基于 localStorage 实现数据缓存 * @param func 该方法执行,可以向服务器发送请求,返回promise实例,并且根据请求结果决定实例的状态 * @param name localStorage存储信息时的key * @param limit 有效期(单位毫秒)默认一小时 */ function cacheStorage(func, name, limit) { if (typeof func !== 'function') throw new TypeError('func is not function'); if (typeof name !== 'string') throw new TypeError('name is not string'); if (typeof limit !== 'number' || isNaN(limit)) limit = 3600000; return new Promise(async (resolve, reject) => { let result = localStorage.getItem(name), now = +new Date(); if (result) { let { time, data } = JSON.parse(result); if (now - time < limit) { // 缓存有效 resolve(data); return; } } // 缓存失效 try { result = await func(); localStorage.setItem(name, JSON.stringify({ time: +new Date(), data: result })); resolve(result); } catch (err) { reject(err); } }); } 复制代码


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有