浏览器往返缓存(Back/Forward cache)问题的分析与解决

博客源地址: https://github.com/LeuisKen/l...
相关讨论还请到源 issue 下。

什么是往返缓存(Back/Forward cache)

往返缓存(Back/Forward cache,下文中简称bfcache)是浏览器为了在用户页面间执行前进后退操作时拥有更加流畅体验的一种策略。该策略具体表现为,当用户前往新页面时,将当前页面的浏览器DOM状态保存到bfcache中;当用户点击后退按钮的时候,将页面直接从bfcache中加载,节省了网络请求的时间。

但是bfcache的引入,导致了很多问题。下面,举一个我们遇到的场景:

浏览器往返缓存(Back/Forward cache)问题的分析与解决_第1张图片

页面A是一个任务列表,用户从A页面选择了“任务1:看新闻”,点击“去完成”跳转到B页面。当用户进入B页面后,任务完成。此时用户点击回退按钮,会回退到A页面。此时的A页面“任务1:看新闻”的按钮,应该需要标记为“已完成”,由于bfcache的存在,当存入bfcache时,“任务1”的按钮是“去完成”,所以此时回来,按钮也是“去完成”,而不会标记为“已完成”。

既然bug产生了,我们该如何去解决它?很多文章都会提到unload事件,但是我们实际进行了测试发现并不好用。于是,为了解决问题,我们的bfcache探秘之旅开始了。

bfcache 探秘

在检索page cache in chromium的时候,我们发现了这个issue:https://bugs.chromium.org/p/c... 。里面提到 chromium(chrome的开源版本)在很久以前就已经将PageCache(即bfcache)这部分代码移除了。也就是说现在的chrome应该是没有这个东西的。可以确定的是,chrome以前的版本中,bfcache的实现是从webkit中拿来的,加上我们项目目前面向的用户主体就是 iOS + Android,iOS下是基于Webkit,Android基于chrome(且这部分功能也是源于webkit)。因此追溯这个问题,我们只要专注于研究webkitbfcache的逻辑即可。

同样通过上文中描述的commit记录,我们也很快定位到了PageCache相关逻辑在Webkit中的位置:webkit/Source/WebCore/history/PageCache.cpp。

该文件中包含的两个方法引起了我们的注意:canCachePagecanCacheFrame。这里的Page即是我们通常理解中的“网页”,而我们也知道网页中可以嵌套