关于缓存和 Chrome 的“新版刷新”
在读本文前你要确保读过我的上篇文章《扼杀 304,Cache-Control: immutable》,因为本文是接着上文写的。上文说到,在现代 Web 上,“条件请求/304 响应”绝大多数都是浪费资源,因为绝大多数静态资源都是永恒不变的,因此 Firefox 实现了 Cache-Control: immutable 来让开发者们控制用户浏览器的刷新行为,即在刷新时不要对这些资源文件进行条件请求(缓存不过期的前提下)。
Chrome 至今迟迟没有实现 Cache-Control: immutable,难道 Chrome 不想让自己的网页在刷新时展现的更快?不是的,其实 Chrome 的开发人员也早已注意到了这个问题。早在 2015 年底,他们就开发出了一种新的刷新行为,称之为 new reload/faster reload/non-validating reload,这种新的刷新和以前传统的刷新有个区别,那就是在刷新页面时,只对页面本身的资源文件进行条件请求(如果缓存了的话),页面里引用的各种子资源文件,只要缓存不过期,就直接读取缓存。也就是说,“你们开发者压根不用去加什么 Cache-Control: immutable 响应头了,我 Chrome 直接改成刷新不发条件请求就得了”。
Chrome 在 2015 年底只针对安卓端的 Chrome for Android 中的下拉刷新开启了这种新的刷新,下面是当时的 commit log:
Make pull to refresh not perform regular reload (with cache revalidation)
Pull-to-refresh action on Android is currently handled as a
regular reload, which causes revalidation of cached contents,
however the action would usually imply that the user wants to
refresh the 'contents' rather than reloading everything (e.g.
to reset the page contents when something's screwed up).
这段话中说到,用户刷新一个页面通常都不是为了重新请求每个资源文件看是不是过期了,而仅仅是为了重置一下页面的状态,所以要做这个优化。下面是当时测试效果的对比演示,左旧右新:

可以看到,左侧有明显的加载白屏阶段,而右侧没有。
在 16 年 5 月份,Chrome 把该刷新行为应用到了 PC 端,从 Chrome 54 开始默认启用。我写了一个测试 demo,在 Chrome 54 之前,刷新这个 demo 后效果是这样的:

所有的资源都会被发起条件请求从而返回 304 响应,而在 Chrome 54 里,刷新这个 demo 后效果成了:
只有页面本身被发起了条件请求,所有引用的子资源都直接读取了缓存,也就是说,实际上刷新这个页面只触发了一个 HTTP 请求。
额外小技巧
从 Chrome 56 开始,你可以通过网络面板新增的 is:from-cache 过滤条件来过滤出直接读取缓存的请求(即没有发送真实的 HTTP 请求的请求),还可以利用它的反向过滤找出发送了真实请求的请求,像下面这样(还是上面的 demo):
这个过滤条件是我向 Chrome 提议的。
不知道你们注意过没有,除刷新外,常规加载一个网页的途径有两种,最常见的一种是通过点击其他页面的超链接(包括浏览器书签)进入当前页面,还有一种是在浏览器地址栏上输入网址并回车(高级用户),这两者在发送请求上也是有区别的。前者是不会发起任何条件请求的(除非缓存过期),而后者是会为页面资源本身发起条件请求的(你可以用上面的 demo 做测试),Chrome 新的这个刷新机制其实就是把刷新改得和在地址栏回车一样了。鉴于现如今的大多页面都是动态页面(没有 Cache-Control/Expires/Last-modified 响应头),不会被缓存,所以如今这三者在 Chrome 上的差别已经很小了。
如果你已经升级到了 Chrome 的最新版,没法找到 Chrome 54 之前的版本来做对比测试,可以试试通过停用 chrome://flags/#enable-non-validating-reload-on-normal-reload 选项来切回老版的刷新,不过这个选项在 Chrome 56 里已经被彻底删除了:

读到这里,有同学就想问了,“难道 Chrome 这样做不违反 HTTP 协议吗?”。并没有,HTTP 协议只会规定客户端应该怎么发一个条件请求,服务器应该怎么响应这个条件请求,但不会规定应用程序何时应该发送条件请求。
那 location.reload() 呢,也会改成新版刷新吗?从 Chrome 56 开始 location.reload() 也会使用新版刷新。HTML 规范并没有明确的说明 location.reload() 应该如何对待缓存,只略略提到了一句:
User agents may allow the user to explicitly override any caches when reloading.
这句话应该是给 Firefox 的 location.reload(true) 准备的。
那对用户来说,这个改动向后兼容吗?从我注意到 Chrome 的这个改动后,一直以为这是 Chrome 的 bug,但提 bug后被告知这是有意的。我当时觉的这个改动太激进了,毕竟打破了二十年多年的浏览器传统,一定会有用户反馈不兼容问题的。但直到这个改动进入稳定版后,也没有一个人反馈。。。仿佛全世界只有我一个人注意到了这个改动。
但对开发者来说,其实这个改动的确是有点不向后兼容的。比如某个带有特定版本号的资源在发布到 daily 环境后,是可以不换版本号(URL)反复覆盖式更新的,但你在浏览器里刷新却看不到效果,只能借助于开发者工具的 Disable cache 功能。不过最终用户是没这个问题的,因为线上是无法覆盖式发布的。
所以现在我的看法变了,Firefox 和其他浏览器应该变的像 Chrome 一样,Cache-Control: immutable 已经几乎没有价值了(除非我漏掉了某个点),能让所有的网页变的更快,为什么不呢。
俗话说的好,“前端有三宝,清缓存、清 cookie、换个浏览器”。以后在 Chrome 里单纯的刷新是真的不行了,要教用户怎么“强制刷新/跳过缓存刷新”了。
可以看到自己公司 CDN 日志的同学们,可以看看最近 304 响应的占比有没有大幅减少,不过国内的话也许需要等国产浏览器的内核更新后才行。
关于缓存和 Chrome 的“新版刷新”的更多相关文章
- chrome最新版49跨域问题
chrome最新版49跨域问题 一.最新版49要用新的参数 加--user-data-dirwindows:"C:\Program Files\Google\Chrome\Applica ...
- vue的组件缓存(返回页面不刷新)
每次使用返回是页面总是会刷新 导致了一些体验上的不愉快 现在 发现vue中的一个很方便的方法还可以用来优化性能就是: keep-alive缓存组件 <router-view v-if=" ...
- 关于如何刷新清除某个特定网站的缓存---基于Chrome浏览器
今天工作时又发现了一个小技巧 1.打开一个网站如:百度 2.打开F12开发者模式 3.右键浏览器的刷新按钮,会出现三个选项:正常重新加载,硬性重新加载,清空缓存并硬性重新加载 正常重新加载 Ctrl+ ...
- [Web前端] mac chrome 浏览器强制刷新,清除浏览器缓存
本文链接:https://blog.csdn.net/zeroyulong/article/details/79806156 mac 强制刷新:command+shift+r mac 普通刷新:com ...
- 【原创】Chrome最新版(53-55)再次爆出BUG!
前言 今年十月份,我曾发布一篇文章<Chrome53 最新版惊现无厘头卡死 BUG!>,不过那个BUG在最新的 Chrome 54 中已经修正. 而今天即将发布的Chrome弱智BUG: ...
- Sublime3和Chrome配置自动刷新网页【实测可用】
SublimeText2下的LiveReload在SublimeText3下无法正常使用,本文整理SublimeText3安装LiveReload的方法.win7下实测可用! 安装成功后,就不需要再手 ...
- 清除IE中Ajax缓存,Chrome不需要
做项目的时候,会遇到这种情况,通过ajax从后台获取的数据在chrome上显示的是最新的,而在IE上却是以前的数据,这是为什么呢,在我百般调试下终于发现原来是因为IE的ajax缓存的原因,于是加上这段 ...
- 用Meta 取消流量器缓存实现每次访问都刷新页面方便调试
如果想禁止浏览器从本地缓存中调阅页面,可以设置网页不保存在缓存中,每次访问都刷新页面,下面是Meta在这方便的用法,需要的朋友可以参考下: <!-- 禁止浏览器从本地缓存中调阅页面.--> ...
- IE/firefox/chrome 每次都刷新
IE FIREFOX 1.在firefox的地址栏上输入about:config回车2.找到browser.cache.check_doc_frequency选项,双击将3改成1保存即可. 那么这个选 ...
随机推荐
- 关键字-super
super可以理解为是指向自己超(父)类对象的一个指针,而这个超类指的是离自己最近的一个父类. class BaseAction { String name; int age; void value( ...
- SQL ALTER TABLE 语句
ALTER TABLE 语句 ALTER TABLE 语句用于在已有的表中添加.修改或删除列. SQL ALTER TABLE 语法 如需在表中添加列,请使用下列语法: ALTER TABLE tab ...
- Golang 入门 : 字符串
在 Golang 中,字符串是一种基本类型,这一点和 C 语言不同.C 语言没有原生的字符串类型,而是使用字符数组来表示字符串,并以字符指针来传递字符串.Golang 中的字符串是一个不可改变的 UT ...
- H5 基于Web Storage 的客户端留言板
<!DOCTYPE html> <html> <head> <meta name="author" content="Yeeku ...
- 软件工程(GZSD2015) 第三次作业
时间: 2015/4/17-2015/4/23 基本要求: 在之前编写的四则运算程序基础之上做如下改进: 请参照教材Page57:4.2-4.3节中内容,修改原程序,使之符合 "代码风格和设 ...
- Mybatis映射文件的自动映射与手动映射问题
Mapper XML 文件 MyBatis 的真正强大在于它的映射语句,也是它的魔力所在.由于它的异常强大,映射器的 XML 文件就显得相对简单.如果拿它跟具有相同功能的 JDBC 代码进行对比,你会 ...
- JDBC数据库连接池之dbcp
一.连接池的作用 数据库的连接是一种很重要的资源,如果一个项目比较小,连接数据库的次数比较少,我们可以采取直连的方式:“获取连接----使用----关闭连接”.但是如果一个网站访问量很大,假如同时有几 ...
- Java多线程10:join()方法
一.前言 通过一个简单的例子引入join()方法 public class Thread01 extends Thread{ @Override public void run() { for(int ...
- Vue学习笔记5
列表渲染 用 v-for 把一个数组对应为一组元素 <div id="app"> <li v-for = "item in array"> ...
- js基础-字符串常用属性合集
/* * * 实例方法---->必须要通过new的方式创建的对象(实例对象)来调用的方法 * 静态方法---->直接通过大写的构造函数的名字调用的方法(直接通过大写的对象名字调 ...

