Libon

什么是 bfcache

7Mins #JavaScript
了解并学习影响页面性能指标的 bfcache 到底是什么

toc

为什么使用 bfcache

Firefox 1.5 版本的时候首次引入了 bfcache,它的主要目的是为了优化用户体验。在用户点击后退或者前进按钮时,浏览器会尝试从缓存中恢复页面,而不是重新加载页面。这可以减少用户的等待时间,提高用户的响应速度。bfcache 在移动端的页面中会比较常见,因为移动端设备的性能相对较低,网络情况也不如 PC 那样稳定,bfcache 可以帮助我们减少页面的加载时间,在不同的页面之间切换也会更快,因为启用了缓存的页面再次访问时不需要重新加载。

怎么判断页面是否进入了 bfcache

在页面中 pageshow 事件都会在 load 事件之后立即触发。pageshow 事件有一个 persisted 属性,如果网页是从 bfcache 恢复的,该属性为 true,否则为 false。您可以使用 persisted 属性来区分常规网页加载和 bfcache 恢复。例如:

初始化
1
window.addEventListener('pageshow', (event) => {
2
if (event.persisted) {
3
console.log('这个页面从bfcache恢复')
4
} else {
5
console.log('页面正常加载')
6
}
7
})

而当页面卸载或浏览器尝试将其放入 bfcache 时,都会触发 pagehide 事件。pagehide 事件也有一个 persisted 属性。如果值为 false,您可以确信相应网页不会进入 bfcache。不过,persistedtrue 并不能保证网页会被缓存。这意味着浏览器打算缓存网页,但可能有其他因素导致无法缓存。

1
window.addEventListener('pagehide', (event) => {
2
if (event.persisted) {
3
console.log('页面*有可能*会进入 bfcache')
4
} else {
5
console.log('页面被正常卸载')
6
}
7
})

如何阻止页面进入 bfcache

利用 bfcache 优化网页

并非所有页面都存储在 bfcache 中,即使某个页面已存储在 bfcache 中,它也不会无限期地保留在此处。浏览器将 bfcache 中的页面保留在内存中,直到达到某个限制,然后开始逐出页面。

使用 pagehide, 而不是 unload

在所有浏览器中针对 bfcache 进行优化的最重要方法是一律不使用 unload 事件监听器。应该监听 pagehide,因为它在网页进入 bfcache 时和在 unload 每次触发时都会触发。

unload 是一项较旧的功能,最初设计是为了在用户离开某个页面时触发。但现在不是了,许多网页仍会假设浏览器以这种方式使用 unload,并且在 unload 触发后,未加载的网页将继续请求。如果浏览器尝试缓存未加载的网页,这可能会破坏 bfcache。

有条件性地增加 beforeunload 事件监听

beforeunload 事件不一定会导致您的网页不符合启用 bfcache 条件。但万事无绝对,所以建议仅在绝对必要的情况下使用,比如满足某些条件的情况下才增加事件监听。beforeunload 的一个示例用例是警告用户,如果他们离开页面,将丢失未保存的更改。在这种情况下,我们建议仅在用户有未保存的更改时添加 beforeunload 监听器,然后在保存未保存的更改后立即移除这些监听器,如以下代码所示:

1
function beforeUnloadListener(event) {
2
event.preventDefault();
3
return event.returnValue = '你确定要退出吗? 未保存的数据将会丢失'
4
}
5
6
onPageHasUnsavedChanges(() => {
7
window.addEventListener('beforeunload', beforeUnloadListener)
8
});
9
3 collapsed lines
10
onAllChangesSaved(() => {
11
window.removeEventListener('beforeunload', beforeUnloadListener)
12
})

避免 window.opener 引用

在旧版浏览器中,如果页面是使用包含 target=_blank 的链接中的 window.open() 打开的,未指定 rel=“noopener”,则打开的页面会引用所打开页面的窗口对象。

除了存在安全风险之外,具有非 null window.opener 引用的页面无法安全地放入 bfcache 中,因为这可能会破坏任何尝试访问该页面的页面。

为避免这些风险,请使用 rel=“noopener” 来阻止创建 window.opener 引用。这是所有现代浏览器中的默认行为。如果您的网站需要打开一个窗口并使用 window.postMessage() 或通过直接引用 window 对象对其进行控制,则打开的窗口和打开器都不符合 bfcache 的条件。

最后

其实通篇看下来,bfcache 也不是什么特别高级的东西,但它确实可以提升一些性能。所以,在需要的时候,还是可以考虑使用一下的,尤其是在一些对性能要求比较高的系统中,比如个人博客,又或者是公司的业务系统。后期优化其实很难,所以这种优化工作应该从一开始就去做,这样即便后期想要做优化,成本也会小很多。

以上。


CD ..