赞
踩
文章目录
缓存机制随处可见,优秀的缓存机制可以缩短网页请求资源的事件,减少延迟,并且由于缓存文件可以重复利用还可以减少带宽,降低网络负荷,从而提高我们的性能优化。
前端缓存主要是指HTTP缓存和浏览器缓存,前端缓存可以加快页面加载速度、减轻服务器负担、减少延迟与网络阻塞、提高用户体验、支持离线使用等,能够有效的提升网站与应用的性能,但同时也面临着缓存过期、用户安全、缓存清除等问题。
http缓存指的是: 当客户端向服务器请求资源时,会先抵达浏览器缓存,如果浏览器有“要请求资源”的副本,就可以直接从浏览器缓存中提取而不是从原始服务器中提取这个资源。
HTTP 缓存分为:强缓存和协商缓存。
浏览器在请求某一资源时,会先获取该资源缓存的header信息,判断是否命中强缓存(cache-control和expires信息),若命中直接从缓存中获取资源信息,包括缓存header信息;本次请求根本就不会与服务器进行通信。状态码为200。可通过设置响应头中的 Cache-Control
和 Expires
字段来控制缓存策略。
强缓存的两种常用设置:
Cache-Control: 是一个用于控制缓存行为的响应头字段。常见的取值有
public
:表示响应可以被客户端和代理服务器缓存。private
:表示响应只能被客户端缓存,中间的代理服务器不能缓存。no-cache
:表示客户端缓存该资源,但在使用之前必须先与服务器确认是否是最新的。max-age=<seconds>
:指定资源在缓存中的最大有效时间,单位为秒
类型 | 描述 |
---|---|
public | 客户端和代理服务器都可以缓存该资源;客户端在xxx秒的有效期内,如果有请求该资源的需求的话就直接读取缓存,status code:200 ,如果用户做了刷新操作,就向服务器发起http请求 |
private | 只让客户端可以缓存该资源,代理服务器不缓存;客户端在xxx秒内直接读取缓存,status code:200 |
immutable | 客户端在xxx秒的有效期内,如果有请求该资源的需求的话就直接读取缓存,status code:200 ,即使用户做了刷新操作,也不向服务器发起http请求 |
no-cache | 跳过设置强缓存,但是不妨碍设置协商缓存;一般如果你做了强缓存,只有在强缓存失效了才走协商缓存的,设置了no-cache就不会走强缓存了,每次请求都回询问服务端 |
no-store | 不缓存,这个会让客户端、服务器都不缓存,也就没有所谓的强缓存、协商缓存了 |
- 示例:
- Cache-Control: max-age:3600, s-maxage=3600, public
- Cache-Control: no-cache
- Cache-Control: no-store
Expires: 是http1.0的规范,是一个响应头字段,表示资源的过期时间,它的值是一个绝对时间的GMT格式的时间字符串。参考时间为浏览器本地时间(也就是说如果人为把电脑时间往后调整该缓存就会过期),浏览器会将这个时间与客户端当前时间进行比较,判断资源是否过期。这个时间代表这这个资源的失效时间,只要发送请求时间是在Expires之前,那么本地缓存始终有效,则在缓存中读取数据。失效的时间是一个绝对时间,当服务器与客户端时间偏差较大时,会导致缓存混乱。如果同时出现Cache-Control:max-age和Expires,那么max-age优先级更高。
Expires: Wed, 01 Jun 2023 12:00:00 GMT
Cache-Control字段要比Expires字段更加准确,当两个字段同时存在与某条响应中浏览器会采取Cache-Control的规则,而Expires更多的意义是为了兼容不支持HTTP/1.1的浏览器使用缓存(如果连HTTP/1.0都不支持的话也用不了缓存机制了)。强缓存的意义是为了减少资源的请求数量,但是有些文件我们无法保证在强缓存有效的时间内不修改,这个时候我们就需要使用协商缓存策略。
总结:
在强缓存生效期间,浏览器会直接从本地缓存中获取资源,并且不会发送请求到服务器。只有当缓存过期或不符合缓存规则时,浏览器才会发送请求到服务器进行验证,即执行协商缓存机制。
强缓存可以有效减少网络请求,提升网页加载速度和用户体验。但需要注意的是,如果设置的缓存时间过长,资源的更新可能不会立即生效,导致用户无法获取最新的资源。因此,在设置强缓时,需要综合考虑缓存时间和资源的更新频率。
协商缓存就是资源在强缓存失效(或者没有设置强缓存)后,浏览器携带特定缓存标识(HTTP请求头中的某些字段)向服务器发送请求,由服务器根据缓存标识决定是否使用缓存的过程。如果缓存可用则返回状态码304以及在响应头中设置对应字段,否则返回新的资源以及状态码为200。和强缓存一样,可以通过两对HTTP的头部字段实现协商缓存:Last-Modified(响应头字段)<—>If-Modified-Since(请求头字段)和Etag(响应头字段)<——>If-None-Match(请求头字段)。
协商缓存的工作流程如下:
1.浏览器发送请求到服务器,请求特定资源。
2.服务器接收到请求后,检查资源的缓存策略,并在响应头中设置缓存验证相关的字段,如 ETag
和 Last-Modified
。
ETag
,浏览器会将其保存下来。3.浏览器收到响应后,检查响应头中的缓存验证字段。
ETag
,浏览器会将其保存下来。Last-Modified
,浏览器也会将其保存下来。4.当浏览器再次请求该资源时,会在请求头中包含缓存验证字段,用于告知服务器上一次请求时使用的标识和最后修改时间。
ETag
值放在该字段中。Last-Modified
值放在该字段中。5.服务器接收到带有缓存验证字段的请求后,进行缓存验证:
ETag
和 Last-Modified
。6.浏览器根据服务器的响应进行处理:
通过协商缓存,可以在资源发生变化时及时更新缓存,减少不必要的网络传输和服务器负载。它与强缓存一起使用,可以提供更灵活和高效的缓存策略,以提高应用的性能和用户体验。
一种在浏览器后台运行的JavaScript脚本,它可以拦截和处理网页发出的网络请求,以及管理缓存和离线数据。Service Worker可以让网页在离线状态下仍能正常访问,并且可以提高网页的性能和响应速度。它由开发者编写的额外的脚本控制,且缓存位置独立。
Service Worker可以实现以下功能:
如果 Service Worker 没能命中缓存,一般情况会使用 fetch() 方法继续获取资源。这时浏览器就去 memory cache 或者 disk cache 进行下一次找缓存的工作了。经过 Service Worker 的 fetch() 方法获取的资源,即便它并没有命中 Service Worker 缓存,甚至实际走了网络请求,也会标注为 from ServiceWorker。
注意:为了保证安全性,Service Worker只能在HTTPS协议下使用。
memory cache(内存缓存)是存储在浏览器内存中的。其优点为获取速度快、优先级高,从内存中获取资源耗时为 0 ms,而其缺点也显而易见,比如生命周期短,当网页关闭后内存就会释放,同时虽然内存非常高效,但它也受限制于计算机内存的大小,是有限的。那么如果要存储大量的资源,这是还得用到磁盘缓存。
disk cache(硬盘缓存)是存储在计算机硬盘中的。其优缺点与 memory cache 正好相反,比如优点是生命周期长,不触发删除操作则一直存在,而缺点则是获取资源的速度相对内存缓存较慢。 disk cache 会根据保存下来的资源的 HTTP 首部字段来判断它们是否需要重新请求,如果重新请求那便是强缓存的失效流程,否则便是生效流程。 获取顺序:
浏览器存储型缓存包含了 Cookie、Web Storage、IndexedDB、WebSQL 等,它们也是我们日常开发中经常会接触的缓存,其是造成“登录一个网站后再次访问的时候就已经是登录状态”现象的主要原因。
Cookie 的存储空间很小,不能超过 4KB,因此这一缺点也限制了它用于存储较大容量数据的能力。 不建议将非用户身份类的数据存储在 Cookie 中,因为 Cookie 在同域下会伴随着每一次资源请求的请求报头传递到服务端进行验证,试想一下如果大量非必要的数据存储在 Cookie 中,伴随着请求响应会造成多大的无效资源传输及性能浪费。 在 Cookie 存储 API 方面,浏览器提供的原始 API 使用起来也不是特别方便,比如:
- // 存储 Cookie
- document.cookie='username=xiaoming; domain=test.fly.com'
-
- // 读取 Cookie
- // 只能通过 document.cookie 读取所有 Cookie 并进行字符串截取,非常不便
-
- // 删除 Cookie
- let date = new Date()
- date.setTime(date.getTime() - 10000) // 设置一个过期时间
- document.cookie=`username=xaioming; domain=test.fly.com; expires=${date.toGMTString()}`
如此操作起来会编写大量重复糟心的代码,因此封装 Cookie 的增删改查操作十分必要。推荐使用 js-cookie 库,其 API 操作如下:
- import Cookies from 'js-cookie'
-
- // 存储 Cookie
- Cookies.set('username', 'xiaoming', { domain: 'test.fly.com' })
-
- // 读取 Cookie
- Cookies.get('username')
-
- // 删除 Cookie
- Cookies.remove('username')
Web Storage 即为 Session Storage 和 Local Storage。
在验证用户身份及维持状态方面,Cookie 有明显的特点和优势,但其并不是存储网页数据的小能手,相反 Web Storage 在这方面却有显著的优势。 Web Storage 作为 HTML5 推出的浏览器存储机制,其又可分为 Session Storage 和 Local Storage,两者相辅相成。 Session Storage 作为临时性的本地存储,其生命周期存在于网页会话期间,即使用 Session Storage 存储的缓存数据在网页关闭后会自动释放,并不是持久性的。而 Local Storage 则存储于浏览器本地,除非手动删除或过期,否则其一直存在,属于持久性缓存。 Web Storage 与 Cookie 相比存储大小得到了明显的提升,一般为 2.5-10M 之间(各家浏览器不同),这容量对于用于网页数据存储来说已经十分充足。 我们再来看一下 Web Storage 相关的操作 API(以 Local Storage 为例):
- // 存储
- localStorage.setItem('username', 'xiaoming')
-
- // 读取
- localStorage.getItem('username')
-
- // 删除
- localStorage.removeItem('username')
在存储简单的数据类型时,Web Storage 提供的原始 API 可以轻松完成任务,但是一旦数据类型变为 Object 类型时,其应付起来就变得捉襟见肘,主要原因在于使用 Web Storage 存储的数据最终都会转化成字符串类型,比如:
- localStorage.setItem('length', 15)
-
- localStorage.getItem('length') // 最终获取的会是字符串 '15'
而存储对象时如果没有提前采用序列化方法 JSON.stringify 转化为字符串对象,那么最终获取的值会变成 [object Object]。 因此 Web Storage 的原始存储方案会存在繁碎的序列化与反序列化的缺点:
- let userinfo = { name: 'xiaoming', age: 18 }
-
- // 存储时进行序列化操作
- localStorage.setItem('userinfo', JSON.stringify(userinfo))
-
- // 获取时进行反序列化操作
- JSON.parse(localStorage.getItem('userinfo'))
我们可以对其API进行二次封装,也可以使用目前 npm 市场上也有相关封装 Web Storage 的包,比如 web-storage-cache。
Web缓存性能优化是一种提高网站加载速度和提高用户体验的方法。通过使用缓存,可以减少服务器的负载和网络延迟,从而提高页面的响应速度。以下是一些关于Web缓存性能优化的建议:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。