DEV Community

Vladimir Elchinov for Session Replay

Posted on

I Tested the "unload Blocks bfcache" Rule and My Page Was Restored Anyway

Microsoft's Edge release notes on 8 October carried an announcement about the unload event: as of Edge 155 the rollout reaches 100% of page loads, and handlers no longer run unless a site opts in through Permissions Policy. The note adds the standard reasoning, that unload "can prevent pages from using the back/forward cache".

Which is the version of this everybody repeats, usually without the "can": register an unload handler and your page is ineligible for bfcache.

I tested it. The page was restored from bfcache anyway.

The test

On a page in Chrome 154, register the handler and a marker, navigate away, navigate back:

window.__log = [];
addEventListener("pageshow", (e) => window.__log.push(`persisted=${e.persisted}`));
addEventListener("unload", () => {});
window.__marker = "1zw4n1";
Enter fullscreen mode Exit fullscreen mode

After going forward to another page and then back:

{ "marker": "1zw4n1", "pageshowLog": ["pageshow persisted=true"] }
Enter fullscreen mode Exit fullscreen mode

persisted=true is the browser telling you directly that this was a back/forward cache restore, and the surviving marker says the same thing a second way: the JavaScript context was never torn down.

So on that browser, on that page, an unload listener did not prevent the restore.

What I am not claiming

One measurement, one browser version, one page, with the handler attached at runtime rather than present in the original source. That is not a new rule, and if you take "unload no longer blocks bfcache" away from this you have swapped one piece of folklore for another.

The eligibility rules differ by engine, by platform, by whether the handler was there at parse time, and now by whether the deprecation rollout has reached that page at all. That last one is new and it is the interesting part: if the handler is never going to fire, there is less reason for it to disqualify anything.

The conclusion is not a rule. It is that this is a question you should stop answering from memory.

Because the browser will just tell you

PerformanceNavigationTiming has a notRestoredReasons property, and it is present in Chrome 154:

const nav = performance.getEntriesByType("navigation")[0];
console.log(nav.notRestoredReasons);
Enter fullscreen mode Exit fullscreen mode

It reads null on a fresh navigation and on a successful restore, and it is populated when the browser tried to restore from bfcache and could not, with the reasons and the frame they belong to. So instead of reasoning about which of your handlers might be disqualifying the page, you ask the page.

Log it once and look at real navigations:

addEventListener("pageshow", (e) => {
  const nav = performance.getEntriesByType("navigation")[0];
  if (!e.persisted && nav?.notRestoredReasons) {
    navigator.sendBeacon("/metrics/bfcache", JSON.stringify(nav.notRestoredReasons));
  }
});
Enter fullscreen mode Exit fullscreen mode

Where it is missing you learn nothing, which is honest, and better than a confident wrong answer.

The part that costs you something

Cache eligibility is the small half. The large half is that the same uncertainty governs whether your exit-time reporting runs at all.

If your analytics or your error reporter batches events and flushes them in an unload handler, then on Edge that code has been running for a shrinking share of page loads since 152 and, from 155, for none of them. No error. No console warning. No failed request. The handler simply is not called.

And the events you lose are a specific set: the last error before somebody left, the queued batch, the "abandoned at this step" signal. The ones about leaving.

Use pagehide and visibilitychange, and sendBeacon rather than fetch, because a beacon is specified to outlive the page. But the migration is not the lesson. The lesson is that you cannot tell from the client whether it worked. A handler that never runs looks exactly like a handler that ran and had nothing to send, and from inside the page both are silence.

So verify it where the evidence survives: count arrivals on the server, grouped by browser major version. If one browser's exit beacons per session fall while its page views do not, you have found it. That number is the only thing in this whole area that cannot be argued with, and it is the one almost nobody plots.

The general shape

A staged deprecation does not announce itself in your logs. It shows up as a slope in a number you are probably not watching, and the thing it takes away is evidence, which is the one category of loss that hides its own size.

Ask the browser what it did. Count what arrived. Do not recite what used to be true.

Top comments (0)