首页 值得一看 🔍️

没有起作用的协商缓存

为什么标题是没有起作用的协商缓存呢?

在回答这个问题之前,小编先给大家简单介绍一下 Vite 开发模式下的缓存策略。在 Vite 中,静态资源分为两类:预构建内容和业务代码。其中,预构建内容通常是由项目中的第三库生成的,采用强缓存策略,业务代码则采用协商缓存策略。

举个 ?:

image.png

图中 chunk-xxx 格式的内容就是预构建内容,响应头中通过 cache-control 字段中的 max-age = 3153600, 指明该文件采用强缓存策略。在请求时,可以通过修改请求的版本号 v=xxxx 来规避强缓存。

image.png

App.tsx,业务代码,采用协商缓存策略。

了解完这个以后,小编就通过 2gif 动图来给大家演示一下为什么说协商缓存没有起作用。

首先是dev server 启动后首次访问应用的 gif 动图。

Nov-04-2022 15-35-09.gif

在这个 gif 动图中,大家可以看到请求静态资源时,会走强缓存和协商缓存。仔细看这些请求,我们会发现在请求 less 类型的文件时,尽管走了协商缓存,但依旧要消耗很长的时间,导致首屏性能受到影响。

image.png

接下来,小编再给大家看一个二次访问应用的 gif 动图。

Nov-04-2022 16-00-47.gif

这次,首屏性能要好很多。打开 network, 我们发现请求 less 类型的文件,只用到了十几毫秒,比之前的 2s 多要好太多了。

image.png

那这是为什么呢?明明返回的状态码都是 304,为什么会是两种效果呢?这里面是有什么说法吗?

答案其实很简单,那就是两次判断 304 的逻辑不一样。

我们知道,协商缓存,通常需要在发起请求时,在请求头中添加 If-None-Match 字段,携带请求文件对应的 ETag 信息。当 dev server 收到请求时,会将请求头的 ETag 和请求文件的 ETag 信息做对比,如果没有变化,返回 304 通知浏览器使用本地缓存,反之则返回新的文件内容。

在获取请求文件的 ETag 信息这一块儿,Vite 有自己的一套处理逻辑。

dev server 内部,有一个缓存对象 - moduleGraph, 用来缓存请求过的文件内容和对应的 ETag 信息。

dev server 启动以后,这个对象是空的。此时如果浏览器发起业务代码请求,dev server 需要根据请求,将请求 url 解析为文件的本地路径(resolve)、读取文件内容(load)、对文件内容做转换(transform - 如 less 转换为 css)、计算 ETag,并缓存到 moduleGraph 中。 此时,如果请求中 If-None-Match 字段中携带的 ETag 信息和新计算的 ETag 信息一致,server 端会将状态码设置为 304,不返回转换以后的内容。

当浏览器再次请求相同文件时,dev server 会根据请求路径直接从缓存中去读取文件内容和 ETag 信息,然后和请求中 If-None-Match 字段中携带的 ETag 信息做比较。如果一致,server 端直接将状态码设置为 304,通知浏览器使用本地缓存。

了解了这些,那么首次访问应用时协商缓存为什么没有起作用就好理解了。因为这个时候,dev server 内部的缓存为空,所有的请求都需要经历 resolveloadtransform 的过程,导致响应耗时较久。

哈哈,是不是很简单呢,?。

结束语

到这里,关于 Vite 开发模式下的缓存策略就介绍完了。

最后,我们做一个简单的总结:

  • 开发模式下,请求预加载文件采用强缓存策略,请求业务文件采用协商缓存策略。

  • 首次访问应用请求业务文件时,尽管会命中协商缓存,但 sever 端依旧会进行 resolveloadtransform 操作,导致响应需要消耗一定的时间。

  • 二次访问应用,强缓存和协商缓存同时起作用,性能很好。

其实,关于结论中提到的第二点,我们还是有办法进行优化的,比如说采取 Webpack5 的缓存策略,在 dev server 关闭之前将 moduleGraph 缓存到本地,等到再次启动时读取本地缓存。这一点,小编将会在后面单独写一篇文章来介绍,感兴趣的小伙伴们可以保持关注哦,?。



文章评论

未显示?请点击刷新