DEV Community

Besworks
Besworks

Posted on

Bizarre bfcache Behavior

For anyone who doesn't know, bfcache is the Back/Forward cache in browsers. I recently fixed an unusual issue in a page that I host that was caused by this.

For multiple years, this site ran fine until suddenly it started misbehaving. Navigating back to a page after following a link would occasionally just reload the current page. Originally I thought this was something wrong with my service worker cache. However, after careful analysis, I discovered the true root of the issue, bfcache.

When a page is restored from bfcache, it is NOT rebuilt using DOMParser. The page is loaded back to the same state at which you left it including any modifications to the DOM and even the console log history is maintained.

In this page I have animations that run when a link is clicked. This flow eventually leads to a tranistionend event that triggers the actual page navigation. Essentially like this, though a good deal more complex with a chain reaction of animations.

button.addEventListener('click', () => {
  layout.addEventListener('transitionend', navigateAway);
  requestAnimationFrame(transitionOut);
});

function transitionOut() {
  layout.classList.remove('in');
}

function navigateAway() {
  location.href = button.url;
}
Enter fullscreen mode Exit fullscreen mode

The issue I was having was that the transitionend event handler was remaining active on page restore, and thus, when the transition IN animations ended after returning to a cached page, that would trigger an immediate location change as if the button was just clicked again. This transitionend handler was lazily not cleaned up since the expectation was for the page to be unloaded immediately after it fired. Properly calling to removeEventListener before the actual navigation cleared the issue right up.

function navigateAway() {
  layout.removeEventListener('transitionend', navigateAway);
  location.href = button.url;
}
Enter fullscreen mode Exit fullscreen mode

Now this is a pretty specific and unusual case, but if you are noticing unexpected behavior in your web apps after page navigation, bfcache restoring your page instead of it reloading may be at the source of it. To confirm if bfcache is causing your troubles, it can be disabled by registering an unload event handler.

window.addEventListener('unload', () => {});
Enter fullscreen mode Exit fullscreen mode

The event handler doesn't need to do anything, just exist. On desktop browsers this makes the page ineligible for bfcache. This is not reliable on mobile browsers and, of course, disabling bfcache is not the right approach to fix some of the other quirks I was seeing. I had to dig deeper.

What I found is that, use of the unload and beforeunload (which I was using for some cleanup) events are no longer recommended and the best way to address this was by handling any state cleanup inside a pagehide event handler and set everything back up in a pageshow event handler.

window.addEventListener('pagehide', event => {
    console.log('saving to bfcache, perform state saving here');
});

window.addEventListener('pageshow', event => {
  if (event.persisted) {
    console.log('restored from bfcache, restore state here');
  } else {
    console.log('normal page load, do fresh page setup');
  }
});
Enter fullscreen mode Exit fullscreen mode

For the best user experience, the above approach is recommended. However, if you absolutely MUST start with a fresh page load for whatever reason. This can be accomplished by triggering a reload after a pageshow event.

window.addEventListener('pageshow', event => {
  if (event.persisted) { location.reload(); }
});
Enter fullscreen mode Exit fullscreen mode

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (0)

AWS Q Developer image

Your AI Code Assistant

Automate your code reviews. Catch bugs before your coworkers. Fix security issues in your code. Built to handle large projects, Amazon Q Developer works alongside you from idea to production code.

Get started free in your IDE

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay