一、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 特性的更多相关文章

  1. 浏览器对HTML5特性检測工具Modernizr

    近期在做公司移动端运营的项目,需求中多处地方都会涉及动画. 相信非常多前端开发都会有这样的感触,对CSS3中的动画属性非常熟悉,可是因为对动画运动过程的理解不深入,经常仅仅能望而止步.CSS3中动画这 ...

  2. [转]JavaScript快速检测浏览器对CSS3特性的支持

    转自:https://yuguo.us/weblog/detect-css-support-in-browsers-with-javascript/ ------------------------- ...

  3. 第四节:教你如何快速让浏览器兼容ES6特性

    写在正文前,本来这一节的内容应该放在第二节更合适,因为当时就有同学问ES6的兼容性如何,如何在浏览器兼容ES6的特性,这节前端君会介绍一个抱砖引玉的操作案例. 为什么ES6会有兼容性问题? 由于广大用 ...

  4. 解决浏览器兼容ES6特性

    为什么ES6会有兼容性问题? 由于广大用户使用的浏览器版本在发布的时候也许早于ES6的定稿和发布,而到了今天,我们在编程中如果使用了ES6的新特性,浏览器若没有更新版本,或者新版本中没有对ES6的特性 ...

  5. 解决让浏览器兼容ES6特性

    为什么ES6会有兼容性问题? 由于广大用户使用的浏览器版本在发布的时候也许早于ES6的定稿和发布,而到了今天,我们在编程中如果使用了ES6的新特性,浏览器若没有更新版本,或者新版本中没有对ES6的特性 ...

  6. JavaScript快速检测浏览器对CSS3特性的支持情况

    项目中使用动画效果在IE9下不支持,所以写了个判断浏览器是否支持动画的函数,进而扩展到下面判断浏览器支持任一特定CSS3属性的函数. function supportAnimation(){ var ...

  7. JS-让浏览器兼容ES6特性

    babel:将 ES6 翻译为 ES5 PS:ie 还不支持 import 和 export 还是用 gulp 打包一下吧

  8. 前端工具-让浏览器兼容ES6特性

    babel:将ES6翻译为ES5 问题: 可以处理import和export么? 不能,还是用Rollup或者webpack打包一下吧 可以处理Promise么? 不能,还是使用babel-plugi ...

  9. 各大浏览器内核特性及对应的Browserhacks举例

    1.浏览器内核指的是什么? 简化的浏览器=用户界面+渲染引擎+js解析引擎+数据存储+网络部件 而通常所说的浏览器内核指的是页面渲染引擎(rendering engine). 2.渲染引擎 The r ...

随机推荐

  1. grep的小技巧

    grep '^[^#]' /etc/openvpn/server.conf 中括号必须匹配一个字符^$属于标志位,不属于字符 grep没把\n看成字符 grep把空行看成^$ 还是perl的标准,空行 ...

  2. softmax_cross_entropy_with_logits

    softmax_cross_entropy_with_logits 原创文章,请勿转载 函数定义 def softmax_cross_entropy_with_logits(_sentinel=Non ...

  3. 【django之用户认证】

    一.auth模块 模块导入 from django.contrib import auth 主要方法如下: 1 .authenticate()    提供了用户认证,即验证用户名以及密码是否正确,一般 ...

  4. Call to undefined function mysql_connect()错误原因

    从PHP5.0开始就不推荐使用mysql_connect()函数,到了php7.0则直接废弃了该函数,替代的函数是: mysqli_connect();

  5. MySQL笔记-语句的执行顺序

    在一次查询线上问题时发现有以下两条同样的SQL,执行后数据的顺序不一样: SELECT * FROM nns_assists_item AS asset WHERE asset.nns_assist_ ...

  6. 终于放弃Windows下丑陋的cmd

    微软万年不变的cmd命令行工具,简直其丑无比,交互性极差.但是作为开发者有时离不开.最近用了几款开源替代方案.发现几款不错的cmd替代者.例如Cmder.babun.ConsoleZ.win-bash ...

  7. 《Thinking in Java》学习笔记(一)

    服务器端的编程可以参考另一本书<企业Java编程>(Thinking in Enterprise Java). 1.基本类型 基本型别 大小 最小值 最大值  默认值 boolean -- ...

  8. BZOJ 4569: [Scoi2016]萌萌哒 [并查集 倍增]

    传送门 题意:长为$n \le 10^5$的数字,给出$m \le 10^5$个限制$[l1,r1]\ [l2,r2]$两个子串完全相等,求方案数 把所有要求相等的位置连起来,不就是$9*10^{连通 ...

  9. BZOJ 1116: [POI2008]CLO [连通分量]

    Byteotia城市有n个 towns m条双向roads. 每条 road 连接 两个不同的 towns ,没有重复的road. 你要把其中一些road变成单向边使得:每个town都有且只有一个入度 ...

  10. vuex学习笔记

    一.vuex的目的 把组件的共享状态抽取出来,以一个全局单例模式管理.在这种模式下,组件树构成了一个巨大的视图,不管在树的哪个位置,任何组件都能获取状态或触发行为. 二.vuex集中式管理数据 安装 ...