前端是如何进行缓存

229 阅读4分钟

浏览器打开页面的时候,会像服务器发起请求,服务器将前端需要的资源文件返回。

这里存在两个关问题:

  1. 浏览器每次请求,服务器都是返回一样的文件,既然都一样为什么每次都要去服务器获取呢?
  2. 浏览器请求服务器资源,需要消耗一定的时间,如何能节省这部分时间呢?

如果把上一次请求的资源文件存储在了本地,下次浏览器直接从本地获取相同的文件

这样既节省了服务器到浏览器的传输时间,又可以拿到相同的文件

这就是缓存

简单说就是本应该从服务器传输回来的文件,可以直接从本地拿到。

缓存有两个概念——强缓存,协商缓存

强缓存

浏览器想要获取某个资源文件,不需要发送请求到服务端,直接读取浏览器的本地缓存。

这个时候看Chrome的Network中显示的HTTP状态码是200。

浏览器会依次去查询——Service Work、Mermory Cache、Disk Cache、Push Cache。

若存在寻找的资源文件,则直接返回;若不存在,继续请求服务器获取文件。

缓存的文件可以拿到了,依旧存在一个问题:

怎么知道这次请求应该从缓存中获取,还是从服务器中获取服务器。万一服务器这个文件有更新,我还拿缓存的,不就出错了么?

在浏览器第一次向服务器发起请求的时候,服务器会在响应头中设置两个属性——Expires或者Cache-Control。

(若同时设置了,这两个属性,会以Cache-Control为主)

Cache-Control的作用就是告诉浏览器,在接下来x时间内不要向我请求了,这次返回给你的文件你自己存好。

比如,设置Cache-Control: max-age=60,就是说60秒内,不要请求服务器。

协商缓存

强缓存解决了,浏览器应该在什么时候请求服务器,什么时候拿缓存的问题。

那么,问题又来了,如果设置的缓存时间超过了,浏览器去请求服务器。

可是这个时候,服务器的文件依旧是旧的,不需要在返回相同的文件给浏览器

浏览器依旧去拿缓存的文件就可以了,所以就引申出来了协商缓存。

简单说,就是浏览器找服务器要资源文件,服务器看了下,发现你浏览器之前的文件就是最新的,不需要在更新了。

服务器告诉浏览器,兄弟,你现在手里的文件还可以用,不用我给你。

浏览器听到后,继续从缓存里面拿文件。

协商缓存有两个种方式

1. Etag/If-None-Match

服务器第一次给浏览器返回资源文件的时候,响应头会带上Etag。

浏览器拿到Etag就会存下来,Etag是一个hash值,他可以唯一标识某个文件。

就像一个人的身份证号码,不管这个人面貌怎么变,只要他的身份证号不变就表示那个人。

只要资源文件内容没发生变化,Etag就不会变。

然后浏览器在强缓存时间Cache-Control过期后,向服务器发起了请求,不过这次请求带着If-None-Match。

If-None-Match的值就是之前服务器返回的Etag的值。

服务器的资源文件发生了更新,Etag就会变化。

服务器通过对于If-None-Match和Etag是否相等。不相等,就返回新的资源文件;相等,服务器不返回资源文件,就返回一个304的状态码

浏览器接收到了304,知道了这次的资源依旧从缓存中获取。

虽然协商缓存依旧需要浏览器和服务器之间的通信,但是服务器的请求返回,只是简简单单返回状态码,又没有携带文件内容,所以速度很快。

就像你去跑步,背着书包跑和不背去跑一样。

2. Last-Modified/If-Modifed-Since

作用和Etag/If-None-Match一样的,区别在于Last-Modified/If-Modified-Since记录的是资源文件的最后修改时间。

浏览器第一次向服务器发起来了请求,服务器返回了资源文件,并且将这个文件的最后更新时间Last-Modified,如2022年6月1日12点。

浏览器接收到了这个时间,之后每次协商请求的时候,都会将这个时间存到If-Modified-Since。

如果这个期间,服务器的资源文件发生了更新,将Last-Modified更新为2022年6月2日12点。

服务器发现Last-Modified和浏览器传过来的If-Modified-Since不一样,他就会返回资源文件。

否则,服务器返回304,浏览器从缓存中拿到文件。

最后放一下流程图: