缓存控制中的 stale-while-revalidate

stale-while-revalidateHTTP RFC 5861中描述的一种 Cache-Control 扩展,属于对缓存到期的控制。

缓存控制

很多人都了解浏览器的缓存机制,这里简单温习一下。为了提高响应速度,浏览器会帮我们把一些请求的响应缓存下来,在下次请求相同的资源时,直接返回缓存的结果。但业务中有些资源时不应该缓存的,应该总是请求最新的结果,浏览器怎么判断哪些资源可以缓存,缓存多久这些信息呢?HTTP 缓存文档中允许服务端设置一些响应头 (如 Cache-control) 来告诉浏览器如何缓存这个响应。

Cache-Control: max-age=600

max-age就是 Cache-control包含的一个指令,用于设置缓存存储的最大周期,超过这个时间缓存被认为过期(单位秒)。比如上面的例子,在 600 秒内,再次请求这个资源,浏览器就会返回缓存的响应,超过这个时间后,请求这个资源,浏览器就会请求新的结果,应用就需要等待这个请求。

含义

那我们回到 stale-while-revalidate=<seconds>。它表明客户端愿意接受陈旧 (stale) 的响应,同时在后台异步检查新的响应 (revalidate)。秒值指示客户愿意接受陈旧响应的时间长度。

怎么样的响应算是陈旧的响应?

stale-while-revalidate指令应当与 max-age配合使用,超过 max-age指定的时间的响应就是陈旧的响应。与之相对的,没有超过时间的就是新鲜的 (fresh) 响应。如果一个缓存的响应没有超过 max-age指定的时间(仍是新鲜的),按照上面讲的缓存机制,此时请求这个资源,浏览器会直接返回缓存的结果。如果缓存的结果已经陈旧了呢?按照前面讲的缓存机制,浏览器应该去请求新的响应了,但是如果存在 stale-while-revalidate指令就不一样了,浏览器会检查这个陈旧的响应是否超过了 stale-while-revalidate规定的时间窗口。如果没有超过,那么浏览器仍然会直接返回缓存的结果,同时在后台请求新的结果用来更新缓存。

有点绕…

我们看 RFC 5861 给出的示例用法。

用法

Cache-Control: max-age=600, stale-while-revalidate=30

这个响应头规定了缓存的周期为 600 秒,可接受 30 秒内的陈旧响应。如果在 600 秒之内请求这个资源,浏览器就会直接返回缓存的响应。如果在 600 秒之后请求,浏览器会检查是否已经超过可接受的陈旧时间,也就是总共是否超过了 630 秒。如果没有超过的话,仍然返回缓存的响应,同时在后台请求新的响应。如果超过了 630 秒,就直接请求新的响应,应用将等待这个请求。

这和直接设置 max-age=630有什么不一样?

我们设想这样一个步骤,比较两种方式的异同。

设置 max-age=630

  1. 初次请求,应用等待请求,得到新鲜的响应,存入缓存
  2. 在 600 秒内再次请求,不用等,得到缓存响应
  3. 在 610 秒时再次请求,不用等,得到缓存响应
  4. 在 640 秒时再次请求,应用等待请求,得到新鲜的响应,存入缓存

设置 max-age=600, stale-while-revalidate=30

  1. 初次请求,应用等待请求,得到新鲜响应,存入缓存
  2. 在 600 秒内再次请求,不用等,得到缓存响应
  3. 在 610 秒时再次请求,不用等,得到缓存响应,同时后台请求了新的响应,存入缓存
  4. 在 640 秒时再次请求,不用等,得到 610 秒时刷新的缓存响应

可以看到我们在 640 秒时的这个请求,即不用等,也保证了新鲜度。实际上,我们在超过 max-age的周期之后,在 stale-while-revalidate指定的时间窗口之内发出的请求,都会得到这个作用。

如果没有恰好在那 30 秒内请求不还是没用么

说对了。600 和 30 这两个数值的搭配可能并不能让你想到实际使用场景,我们来举一个实例。

实例

假设我有一个 HTTP API,它返回现在是当前小时的第几分钟。它具有如下缓存控制响应头:

Cache-Control: max-age=1, stale-while-revalidate=59

如果在 1 秒钟内重新请求,那么分钟数和原来是一样的,之前缓存的结果完全是新鲜的;如果在 1-60 秒内请求,需要请求一个新的结果了,但原来的结果也不是不能用;如果在超过 60 秒后请求,则一定需要新的结果。

从这个例子可以看出,stale-while-revalidate比较适用的场景是,我们查询的信息需要被刷新,但一定程度的陈旧是可以接受的。通常来讲,这种场景对应的业务是,我们请求的会资源在已知的或者可预见的周期内定时更新,同时我们会多次请求这个资源。在这样的场景下,stale-while-revalidate可以在提供新鲜度有保证的响应结果的同时,减少重复请求的等待时间。

等等,这听起来有点像…

我们在开发应用时,为了减少请求的等待时间,减少空白页的出现,有时会在请求完成后,按照请求的 URL 等标识,将请求结果存储在 Redux/Vuex 等介质中,在页面上从 store 中读取数据来显示,而不是直接在 state 中维护和显示请求结果。这样一来,当需要重新请求相同的资源时,我们可以在界面上看到上次请求的结果,随后看到新的结果,减少空白页的出现。

如果你也有这样的操作,或者想要有这样的操作,不妨看看 zeit 的 swr库,它已经帮你做了。swrstale-while-revalidate的缩写,虽然得名于此,swr只是借用了它的思想,实际实现与 stale-while-revalidate指令并无关系。swr在早读课的另一篇文章有介绍。这里不多赘述。

浏览器兼容性

stale-while-revalidate不是缓存标准文档的一部分,而是扩展内容,属于实验性质。目前桌面浏览器只有 Chrome 75、Firefox 68、Edge 79 起对其有支持。

总结

缓存控制是应用优化中一个通用的、常用的方法,它不是单纯的前端技术或知识,也并非一夜之间就能一把梭的方法。很多时候缓存控制应该结合实际业务需求,对各个资源有针对性地使用,以在信息的准确性和响应的时间上达到最佳的平衡。

最后分享一句格言,它是 Google Web 指南里的一个章节标题。

Never load the same resource twice.

参考链接

原文链接:juejin.im

上一篇:Vue首屏优化记录
下一篇:关于css打印分页

相关推荐

  • 马蜂窝推荐系统容灾缓存服务的设计与实现

    数据库突然断开连接、第三方接口迟迟不返回结果、高峰期网络发生抖动...... 当程序突发异常时,我们的应用可以告诉调用方或者用户「对不起,服务器出了点问题」;或者找到更好的方式,达到提升用户体验的目的...

    1 年前
  • 项目中资源缓存机制实践(静态资源和本地数据缓存)

    网络资源的缓存 核心方案 1. HTML文件 nocache 2. js,css文件 时间戳/哈希/版本号,长缓存 3. 图片资源 长缓存,更新时使用新链接地址 1. 前后端...

    1 年前
  • 面试官问我:说说你对浏览器缓存的理解

    缓存类型 强缓存 定义: 当发起HTTP请求时,不会向服务器进行请求,只要当前时间在缓存有效期内,则直接从客户端缓存中获得,当缓存过期之后,才会真正想服务器发起请求重新获得资源。

    18 天前
  • 面向校招 HTTP与前端缓存知识点总结

    一. 基础概念 HTTP 特点 简单快速:请求服务时,只需传送请求方法和路径 灵活:允许传输任意类型的数据对象,由 ContentType 标记 无连接:服务端处理完请求就断开连接 无状态:意味着每...

    6 个月前
  • 除夕小谈浏览器缓存

    更好的阅读体验 = 点击文末左下角的阅读原文 什么是浏览器缓存? (https://img.javascriptcn.com/bbc4d1d4cf4052345db362e4f3485191...

    1 年前
  • 防止浏览器缓存ajax调用结果

    Mark BellSalamander2007(https://stackoverflow.com/users/43140/markbell)提出了一个问题:Prevent browser cachi...

    2 年前
  • 防止requirejs缓存所需的脚本

    BumbleB2na(https://stackoverflow.com/users/285714/bumbleb2na)提出了一个问题:Prevent RequireJS from Caching ...

    2 年前
  • 重新学习浏览器缓存

    浏览器如何缓存资源? 首先缓存按照位置可以分为:service worker、memory cache、disk cache (/public/upload/3c0180c14b33102d04d...

    6 个月前
  • 通过参数缓存清除

    Brad Herman(https://stackoverflow.com/users/259628/bradherman)提出了一个问题:Cache busting via params,或许与您遇...

    2 年前
  • 通俗易懂的浏览器缓存讲解

    (https://img.javascriptcn.com/c5cf6c57c2dc72a27240fb0c7dbc9814) 写作背景 在网络上,介绍信息类,传递资讯类的文章有很多,但真...

    9 个月前

官方社区

扫码加入 JavaScript 社区