浏览器的 bfcache 特性
一、bfcache 基本概念
现代浏览器在根据历史记录进行前进/后退操作时,会启用缓存机制,名为“bfcache”(back-forward cache,往返缓存),它使页面导航非常快。直到用户关闭浏览器,这个缓存状态才会被删除。
从 MDN 上得知,支持 bfcache 特性的 Firefox 浏览器,对于一个简单的浏览器会话,会缓存全部页面到内存中,包括他们的JavaScript状态。直到用户关闭浏览器,这个缓存状态才会被删除。bfcache 是一种浏览器优化,但是 HTML 标准中并未指定浏览器如何进行缓存,因此不同的浏览器的缓存策略也与 Firefox 的不同。
MDN 上还指出一些Firefox不会缓存页面的情况,如下:
- 页面绑定了 unload 或 beforeunload 事件;
- 页面设置“cache-control: no-store”;
- 站点是HTTPS且页面至少存在一个如下设置:
- “Cache-Control: no-cache”
- “Pragma: no-cache”
- “Expires: 0”或赋予“Expires”一个相对于“Date”的过去日期(除非“Cache-Control: max-age=”也定义了)
- 当用户导航离开页面时,该页面没有完全加载,或因为其他原因等待网络(例如,XMLHttpRequest);
- 页面执行IndexedDB事务;
二、不同浏览器中的不同策略
1. 测试设计
测试页面有两个,代码分别如下。
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Page 1</title>
</head>
<body>
<img src="//static.symind.top/images/fruit.png">
<p>Page 1.</p>
<a href="page2.html">Go to page 2.</a>
<script>
var p = document.createElement('p');
document.body.appendChild(p); var i = 0;
var time = setInterval(function () {
p.innerText = i++;
}, 1000); window.onload = function () {
alert('onload...');
}
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Page 2</title>
</head>
<body>
<p>Page 2.</p>
<a href="javascript:goback()">后退</a>
<script>
function goback () {
window.history.back();
}
</script>
</body>
</html>
2. 测试结果
| 浏览器 | 版本 | 是否缓存 DOM | 是否缓存页面中的静态资源 | 是否缓存 js 执行状态 | 是否触发 load 事件 |
| Desktop Chrome | 60.0.3112.101(正式版本)(64 位) | 否 | 是 | 否 | 是 |
| Desktop Firfox | 58.0.2(64位) | 是 | 是 | 是 | 否 |
| QQ浏览器 | 8.2.0.3950(安卓版) | 是 | 是 | 是 | 否 |
注意:缓存 js 执行状态表示离开当前页面时,js 将停止执行,返回后会继续执行。现在的很多手机浏览器并非使用 bfcache 特性来提高页面导航速度,而是将每个页面都封装成类似于一个 WebView 的形式,如,小米手机浏览器。而使用这种方式的浏览器,即使离开页面后,js 仍会继续执行,且不会触发下面介绍的 pageshow 与 pagehide 事件。
备注:在 Desktop Chrome 触发了“往返缓存”时,在开发者工具中能看到 HTTP 请求的状态码(Status Code)为 200 OK (from disk cache),如下图。

三、新的事件
尽管由于内存中保存了整个页面的状态,不触发load事件也不会导致什么问题,但为了更形象地说明 bfcache 的行为,浏览器还提供了一些新事件 pageshow 和 pagehide。

1. pageshow 事件
该事件与 load 事件相似,但是它在页面的每次加载时都会触发(当页面触发 bfcache 特性使用缓存加载时 load 事件不会被触发)。页面第一次加载时,pageshow 事件紧随着 load 事件之后触发。pageshow 使用一个布尔类型属性名为 persisted,在初始化加载时它的值为 false。当页面并非初始化加载时,它的值为 true(话句话说,当页面被缓存时它的值为 true)。
2. pagehide 事件
如果你想在用户导航离开页面时定义一些行为,但你不想使用 unload 事件(这会导致页面不会被缓存),你可以使用新的 pagehide 事件。与 pageshow 事件相同,pagehide 事件也使用一个布尔类型属性名为 persisted。如果页面没有被缓存,该属性的值为 false,如果页面被缓存,该属性的值为 true。当该属性的值为 false 时,unload 事件处理器进行处理,反之,pagehide 事件会在 unload 事件触发后立即触发。
四、实际业务相关
1. 业务背景简述
第一个网页提供根据城市提供服务种类列表,假定为 catePage。点击其中一种服务种类将跳转至该服务种类下的详细服务列表,假定为 servicePage。其中在 servicePage 中可以切换城市,业务要求在 servicePage 切换城市返回到 catePage 时要求刷新该页面的城市信息。如下图所示。

2. 解决方案
解决的思路很简单,当页面处于非初始化加载时,进行相关的进行更新城市信息的操作。
对于使用 bfcache 的浏览器可以添加 pageshow 事件,并结合该事件中的 persisted 属性在对于非初始化加载的情况下进行对城市信息的相关处理。
而对于小米浏览器这样,将每个页面都封装成类似于一个 WebView 的形式的手机,使用 visibilitychange 事件。该事件配合 load 事件能够判断是否为初始化加载,配合 document.hidden 属性能够判断页面显示状态。
参考文章
1. Using Firefox 1.5 caching:https://developer.mozilla.org/en-US/Firefox/Releases/1.5/Using_Firefox_1.5_caching
2. 浏览器前进/后退缓存(BF Cache): http://harttle.land/2017/03/12/backward-forward-cache.html
3. Can I use:https://caniuse.com/#search=pageshow
浏览器的 bfcache 特性的更多相关文章
- 浏览器对HTML5特性检測工具Modernizr
近期在做公司移动端运营的项目,需求中多处地方都会涉及动画. 相信非常多前端开发都会有这样的感触,对CSS3中的动画属性非常熟悉,可是因为对动画运动过程的理解不深入,经常仅仅能望而止步.CSS3中动画这 ...
- [转]JavaScript快速检测浏览器对CSS3特性的支持
转自:https://yuguo.us/weblog/detect-css-support-in-browsers-with-javascript/ ------------------------- ...
- 第四节:教你如何快速让浏览器兼容ES6特性
写在正文前,本来这一节的内容应该放在第二节更合适,因为当时就有同学问ES6的兼容性如何,如何在浏览器兼容ES6的特性,这节前端君会介绍一个抱砖引玉的操作案例. 为什么ES6会有兼容性问题? 由于广大用 ...
- 解决浏览器兼容ES6特性
为什么ES6会有兼容性问题? 由于广大用户使用的浏览器版本在发布的时候也许早于ES6的定稿和发布,而到了今天,我们在编程中如果使用了ES6的新特性,浏览器若没有更新版本,或者新版本中没有对ES6的特性 ...
- 解决让浏览器兼容ES6特性
为什么ES6会有兼容性问题? 由于广大用户使用的浏览器版本在发布的时候也许早于ES6的定稿和发布,而到了今天,我们在编程中如果使用了ES6的新特性,浏览器若没有更新版本,或者新版本中没有对ES6的特性 ...
- JavaScript快速检测浏览器对CSS3特性的支持情况
项目中使用动画效果在IE9下不支持,所以写了个判断浏览器是否支持动画的函数,进而扩展到下面判断浏览器支持任一特定CSS3属性的函数. function supportAnimation(){ var ...
- JS-让浏览器兼容ES6特性
babel:将 ES6 翻译为 ES5 PS:ie 还不支持 import 和 export 还是用 gulp 打包一下吧
- 前端工具-让浏览器兼容ES6特性
babel:将ES6翻译为ES5 问题: 可以处理import和export么? 不能,还是用Rollup或者webpack打包一下吧 可以处理Promise么? 不能,还是使用babel-plugi ...
- 各大浏览器内核特性及对应的Browserhacks举例
1.浏览器内核指的是什么? 简化的浏览器=用户界面+渲染引擎+js解析引擎+数据存储+网络部件 而通常所说的浏览器内核指的是页面渲染引擎(rendering engine). 2.渲染引擎 The r ...
随机推荐
- AI_深度学习概论
什么是是神经网络? 假如有6间房屋的数据集,已知房子的面积,单位是平方米或平方英尺,已知房子的价格.如果通过这6间房子的价格和房子的面积,预测房子的价格,首先要建立起一个数据模型 ,x轴为价格,y轴为 ...
- JAVAEE——BOS物流项目01:学习计划、搭建环境、主页设计(jQuery EasyUI)
1 学习计划 1.项目概述 项目背景介绍 2.搭建项目开发环境 数据库环境 maven项目搭建 svn环境搭建 3.主页设计(jQuery EasyUI) layout页面布局 accordion折叠 ...
- Java中Unsafe类详解
http://www.cnblogs.com/mickole/articles/3757278.html Java不能直接访问操作系统底层,而是通过本地方法来访问.Unsafe类提供了硬件级别的原子操 ...
- java1.8--Optional类
身为一名Java程序员,大家可能都有这样的经历:调用一个方法得到了返回值却不能直接将返回值作为参数去调用别的方法.我们首先要判断这个返回值是否为null,只有在非空的前提下才能将其作为其他方法的参数. ...
- CRC检验
CRC(循环冗余检验码) 基本原理:在K位信息码后面加上R位校验形成N位编码(即CRC码),事先需要约定一个生成多项式G(x),校验码生成过程:将K位信息码向左移动R位然后mol(其实就是按位异或)上 ...
- Android 使用android-support-multidex解决Dex超出方法数的限制问题
随着应用不断迭代,业务线的扩展,应用越来越大(比如集成了各种第三方sdk或者公共支持的jar包,项目耦合性高,重复作用的类越来越多),相信很多人都遇到过如下的错误: UNEXPECTED TOP-LE ...
- JSP -java service pages
jsp的运行机制: 1客户端(请求jsp页面)------->JSP页面(转换为java源文件)------->Selvet文件(.java) (编译成相应的字节码文件也就是后缀名是.cl ...
- 使用CefSharp开发一个12306“安心刷票弹窗通知”工具
有需求就要改进 最近两年没有在春节回家过年了,主要是票太难买,虽然之前写了一个12306“无声购票弹窗”工具,解决了抢票问题,但是全家老小一起回去还是很累,干脆就在北京过年了.这两天突然有一个朋友问我 ...
- 用swing做一个简单的正则验证工具
直接上代码吧,因为我对swing也不熟悉,照着API一点点拼出来的. import java.awt.event.ActionEvent; import java.awt.event.ActionLi ...
- 基于SpringMVC+Mybatis搭建简单的前后台交互系统
前面博文有一篇 名为基于tomcat+springMVC搭建基本的前后台交互系统(http://www.cnblogs.com/hunterCecil/p/6924935.html),例文中使用了Io ...