bfcache 全称是Back/forward cache,指浏览器在前进/后退的过程中,现代浏览器在通常情况下会缓存住页面在内存中,用来提高页面加载速度和用户体验。
但既然是缓存,那么一段会存在缓存是否有效的问题。bfcache 也一样,在一些特地场景下,如果强制缓存住页面,可能会导致意料之外的问题,所以bfcache 的生效也有一些限制。如果想详细了解bfcache,可以浏览https://web.dev/bfcache/。
当在一个文章列表页中,点击了一个外链跳转的其他的页面后,再点击返回,我们可能期待的是:返回有页面不用重新加载,并且滚动条在原来的位置处。
如果是支持bfcache 的场景下,因为页面是被缓存住的,js 并没有执行,没有重新渲染,以上效果是可以达成的。
然而,由于在微信当中,微信的IOS 版本是wkwebview,支持bfcache,但在微信的安卓浏览器中,却是不支持bfcache的,为了达到相同的用户体验,无奈之下只能用js 来实现。
实现的思路也比较简单:
- 在用户跳转外链之前,把js store 中的数据和滚动条位置持久化保存在本地。
- 判断用户是通过返回键回到页面,且本地存在持久化数据,则还原本地数据,不发起网络请求。
- 为了防止本地持久化数据异常对用户造成影响,使用sessionStorage,用户关闭页面后会被自动清空。
以上方案目前运行良好,安卓使用js 模拟bfcache,IOS 使用原生的bfcache。
但后来遇到一个问题,网上查了很久也没有资料,花了很多时间,于是记录一下。
经过几天的功能迭代,IOS 的bfcache 在部分页面突然失效了。排查了可能让bfcache 失效的一堆原因,并没有找到问题。最后注释掉微信分享相关的代码,发现bfcache 恢复,于是去查看了相关源码,找到了一部分可疑代码。
在实现微信分享的过程中,我使用了一个开源的第三方库 wechat-jssdk,查看这个库的源码,发现他在每次初始化库的时候,会先执行一个`loadScript` 的函数去动态加载js。
怀疑是这段动态加载微信js sdk 的代码导致的bfcache 失效,虽然chrome 相关文档没有找到动态加载js 会导致bfcache 失效的相关介绍,但缓存中被执行了新的js ,很可能会失效。
loadScript() { return new Promise((resolve, reject) => { const ele = document.createElement('script'); ele.type = 'text/javascript'; ele.async = true; ele.onload = () => { console.log('Wechat script loaded successfully!'); //init the wechat config this.signSignature() .then(instance => { resolve(instance); }) .catch(err => { reject(err); }); }; ele.onerror = err => { console.error('Failed to load wechat script!'); console.error(err); this.debug && alert('Cannot load wechat script!'); reject(err); }; const linkEle = document.getElementsByTagName('script')[0]; linkEle.parentNode.insertBefore(ele, linkEle); ele.src = this.sdkUrl; }); }
于是注释掉这段代码,直接在head 中引入js sdk ,问题终于得到了解决。