0% found this document useful (0 votes)
140 views

Back-Forward Cache - Web-Exposed Behaviour

This document outlines the web-exposed behavior of back/forward cache across Chromium, Safari, and Firefox browsers. It discusses how pages are handled when navigating into and out of the back/forward cache, including which events are fired. The goal is to standardize this behavior and improve cross-browser compatibility. Key differences between browsers are highlighted, such as how event listeners and navigation timing are handled. Plans are described to address compatibility concerns when deprecating the unload event in favor of new events.

Uploaded by

Mariano Bozzani
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
140 views

Back-Forward Cache - Web-Exposed Behaviour

This document outlines the web-exposed behavior of back/forward cache across Chromium, Safari, and Firefox browsers. It discusses how pages are handled when navigating into and out of the back/forward cache, including which events are fired. The goal is to standardize this behavior and improve cross-browser compatibility. Key differences between browsers are highlighted, such as how event listeners and navigation timing are handled. Plans are described to address compatibility concerns when deprecating the unload event in favor of new events.

Uploaded by

Mariano Bozzani
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 9

Back/forward cache: web-exposed behaviour

[email protected]
Jul 21, 2020

Summary
Back/forward cache is a browser feature which improves the user experience by keeping a page
alive after the user navigates away from it and reuses it for session history navigation (browser
back/forward buttons, history.back(), etc) to make the navigation instant. The pages in the
cache are frozen and will not run any javascript.

This document outlines the web-exposed behaviour of back/forward cache and the
implementation differences between Chromium, Safari and Firefox. The goal is to standardize
the behaviour and improve the interoperability.

See Chrome launch plans section for more details about Chrome’s bfcache launch timeline.

Cross-browser support
Both Safari and Firefox implement back/forward cache. However, their implementations vary
substantially — as a rule of thumb, Safari stores the page in the cache in more situations,
prioritising better user experience, while Firefox avoids storing the page in the cache in
uncertain situations, prioritising platform predictability.

Page lifecycle
When the user tries to navigate away from the page, the following events will be dispatched:
● beforeunload
○ The user might be prompted to confirm the navigation. If the user rejects the
prompt, navigation is aborted. If the user accepts the prompt, the navigation
continues as normal.
● visibilitychange if the page wasn’t hidden
● pagehide
● If the browser attempts to store the page in bfcache:
○ freeze
● Otherwise:
○ unload
After the freeze event the page is frozen and no events will be dispatched until the page is
restored from bfcache. If a task or a promise associated with a page’s document become ready
during this period, they will run after the page is restored from the cache.

While the page is in the cache, the user agent at any point in time can decide to evict the page in
the cache. In this case the page will be destroyed without any notifications being dispatched.

When the page is navigated back to, the following events will be dispatched:
● resume
● pageshow
● visibilitychange if the navigation happened in a visible tab

Event listeners

pageshow/pagehide
[tester, spec]

event argument of both pageshow and pagehide has event.persisted property.

For pageshow event.persisted is true iff the page was restored from back/forward cache.

For pagehide if event.persisted is false, the user navigates away from the page and the
user agent will not try to store the page in the cache. If event.persisted is true, the user
agent will try to persist the page in the back/forward cache, but it might or might not happen.

Both Safari and Firefox implement these events.

visibilitychange
[tester, spec]
If the page was stored in the cache while the tab was in the foreground, visibilitychange
event will be dispatched. document.visibilityState will be set to hidden.

If the page was restored from the cache while the tab was in the foreground,
visibilitychange event will be dispatched. document.visibilityState will be set to
visible.

Safari does not dispatch visibilitychange when the page is moved to or from the cache.
Firefox dispatches visibilitychange event.

freeze / resume
[tester, spec, API explainer]
freeze will be the last event to be dispatched before the frame is frozen. After freeze event is
dispatched, no javascript will run until the page is restored from the cache and resume event
fires.

Safari and Firefox do not support freeze/resume event listeners.

beforeunload
[tester, spec]
beforeunload will fire during the normal navigation flow before bfcache eligibility for a
document is determined. beforeunload will fire both for same-site and cross-site navigation.

In Firefox, presence of beforeunload event listener makes page ineligible for bfcache.
In Safari, presence of beforeunload event listener does not affect page eligibility. Safari will
fire beforeunload only for same-site navigations.

unload
[tester, spec]
If the user agent decides to attempt to store the page in the back/forward cache (as indicated
by pagehide’s event.persisted attribute being set to true), the unload event will not be
dispatched.

This is going to be the biggest compat concern for existing websites given that ~60% of page
loads register unload event listener. The risk is already mitigated by:
a) unload already not firing on mobile in some circumstances (e.g. background tab killed
by OS)
b) Safari already not firing unload when the page is stored in the back/forward cache
c) unload’s bfcache-friendly analogue, pagehide, is registered for ~36% of page loads.
d) almost all possible breakage will not be user-visible and will mostly affect metrics.

Our plan is further mitigate the risk is as follows:


● We will add a console warning and a Lighthouse report when unload event listener is
registered.
● We will start with enabling back/forward cache on Android for cross-site navigations.
The presence of the unload event listener will not affect cache eligibility.
● As a next step, we will enable back/forward cache on Android for same-site navigation.
The presence of the unload event listener will make the page ineligible for same-site
bfcache.
● And finally after we will make pages with unload event listeners being eligible for being
cached after same-site navigations.

Our long-term aspiration is to deprecate unload() event and eventually remove it completely in
favour of visibilitychange and pagehide.
In Firefox, presence of unload event listener makes a page ineligible for bfcache.
In Safari, presence of unload event listener does not affect page eligibility. `unload` will not be
fired when the page is stored in the back/forward cache.

Eligibility criteria
If any of the following is true, user-agent will not attempt to store the page in the back/forward
cache. Note that this is not exhaustive:
● Status of the http request of the main resource of the main document was not 200 OK.
● Method of the http request of the main resource of the main document was not GET.
● Scheme is not HTTP or HTTPS.

Opting out from back/forward cache

Cache-control: no-store
Presence of Cache-control: no-store header on the main resource of the main document of the
page will disable back/forward cache.

Note that Cache-control: no-cache as well as Cache-control: no-store for subframes or


subresources do not affect cache eligibility.

Safari 14 does not cache pages iff main document’s main HTTP request’s response has
Cache-Control: no-store header. (Note that this changed in Safari 13, which cached all pages
regardless of the presence of Cache-Control: no-store header).

TODO: Confirm using Safari 14.

Firefox does not cache pages with main resources having Cache-Control: no-store or
Cache-Control: no-cache directive [confirm].

Explicit opt-out
We are gathering feedback from other browsers and web developers to see if there is a need for
adding an explicit JS API for making bfcache as ineligible. Github thread:
https://github.com/whatwg/html/issues/5744

In Chrome, user-level opt-out is available via chrome://flags#back-forward-cache, as well an


enterprise policy-based opt-out.
Integration with web platform features

window.open
[tester, spec]
Only pages which have a trivial browsing context group (browsing context group that does not
contain auxiliary browsing contexts). That means that pages which either have a handle to a
valid WindowProxy object (i.e. have used window.open to open) or non-null window.opener (i.e.
have been opened by a different page) are not eligible for being stored in the back/forward
cache.

This applies regardless of same-origin access policy, so both cross-origin and same-origin
window.open will make both target and source page ineligible for bfcache. However, if the
opener relation is severed (Cross-Origin Opener Policy, rel=noopener, etc), a new browsing
context group is created and both pages will be eligible for bfcache.

To ensure that each page will get its own browsing context group, Chromium will proactively
swap browsing context group on top-level cross-document navigation if the browsing context
group of the old page was trivial.

We will not implement support for caching pages with non-trivial browsing context groups due
to associated complexity.

TODO: Confirm Safari behaviour.


Firefox caches pages with window.open references.

Plugins
Pages with embedded plugins are ineligible for being stored in the back/forward cache.

TODO: Confirm Safari and Firefox behaviour here.

setTimeout/setInterval
[tester, spec]
Timers will be suspended when the page enters back/forward cache. The timer callbacks will be
dispatched after the page is restored from back/forward cache.

Chromium considers timer delays to be “real-time”, so the time page spends in back/forward
cache is taken into account when firing the timer (if the delay is 15 seconds and the page spent
10 seconds in the back/forward cache, the timer will fire after 5 seconds after the page is
restored from the cache).
Safari and Firefox consider timer delays to be “page-active time” and in the previous example
the timer callback will fire after 15 seconds after the page is restored from back/forward cache
and 25 seconds after the timer was queued.

window.postMessage()
As pages with non-trivial browser context groups are ineligible for bfcache (see window.open),
it’s impossible to use window.postMessage() to send a message to a page in the back/forward
cache.

navigation timing
`window.performance.timing` (NavigationTiming API v1) will not change, including
timing.navigationStart — it will always correspond to the navigation start of the original page
load, even after bfcache restore. Note: Firefox does the same, Safari updates
timing.navigationStart to correspond to the navigation start of the back/forward cache restore
navigation.

In the long term plan, we are planning to expose navigation timing of the bfcache restore
navigations via Navigation Timing API v2, however at the moment the exact need and the
desired shape for this API is not understood. Interested web developers are encouraged to
contact us and share their use cases with us.

As a short term solution, we will set the timestamp of the `pageshow`’s `event` to the timestamp
of the navigation start of the back/forward cache restore navigation.

DedicatedWorker
[tester, spec]
At the moment the presence of a DedicatedWorker makes page ineligible for bfcache in
Chromium.

Note: we are planning to consider supporting pages with DedicatedWorkers by pausing the
script execution in the workers.

Firefox caches pages with DedicatedWorkers, Safari does not.

SharedWorker
At the moment the presence of a SharedWorker makes the page ineligible for bfcache in
Chromium.

TODO: Confirm Safari’s and Firefox’s behaviour.


ServiceWorker

Pages with ServiceWorker are eligible to be cached.

ServiceWorker can’t see the clients in back/forward cache: clients.get() and clients.matchAll()
will not return handles to the clients which are in back/forward cache. Old handles returned
from previous invocations of clients.get() / clients.matchAll() will continue to work after the
page was restored from the cache, but an attempt to send an event via client.postMessage() will
cause the page to be evicted from the back/forward cache.

If ServiceWorker tries to claim all clients via clients.claim(), all cached unclaimed clients will be
evicted from back/forward cache.

TODO: Confirm Safari & Firefox behaviour here.

Network access: fetch / XMLHttpRequest / WebSocket / WebRTC


[tester]

At the moment a presence of an active outstanding network request will make the page
ineligible for back/forward cache.

Note: in the medium term we are planning to consider supporting pages with outstanding
network requests by aborting them.

Firefox does not cache pages with active network requests.


Safari caches such pages but cancels active network requests.
https://chromium-review.googlesource.com/c/chromium/src/+/3222281

BroadcastChannel
At the moment the presence of the BroadcastChannel will make the page ineligible for bfcache.

Note: in the medium term we are planning to consider supporting pages with BroadcastChannel
by automatically disconnecting the page from the BroadcastChannels when the page enters
back/forward cache.

TODO: Confirm Firefox’s and Safari’s behaviour here.

IndexedDB & WebLocks


The pages having active IndexedDB transactions or WebLocks will not be eligible for bfcache.
We do not have plans to start caching the pages with active IndexedDB or WebLocks unless the
page cleans it proactively itself.

TODO: Confirm Safari’s and Firefox’s behaviour.

Focus
When we navigate away from a page and it gets stored into the back/forward cache, we will
remove the focus from the currently focused element (and trigger blur event, etc.). When we
navigate back and restore the page from the back/forward cache, the focus will not be restored.

On Safari and Firefox, the focus will be kept on the focused element, so when we navigate back
and restore the page, the previously focused element will stay focused.

TODO: Confirm Safari’s and Firefox’s behaviour regarding focus-related events, and maybe
reconsider Chrome’s implementation for interoperability.
See spec issue: https://github.com/whatwg/html/issues/5878

Other APIs
A number of other complex APIs, including WebUSB, WebBluetooth, IdleManager, WebGL,
WebVR, WebXR, audio- and video-capturing APIs and others will make page ineligible for
back/forward cache.

In the very short term, many APIs will prevent pages from being eligible for bfcache if they were
used at any point during the page’s lifetime (for example, all pages requesting a feature
depending on the notification permission will not be cached).

In the short-to-medium plan we will ensure that the page can be stored in the back/forward
cache if the page has performed a cleanup of these APIs in pagehide() or freeze() handler.

Chrome launch plans

Mobile support
● Back/forward cache for cross-site navigations on Android in Chrome 86.
● Back/forward cache for same-site navigations on Android in a follow-up milestone.

Desktop support
Chrome is aspiring to enable back/forward cache on desktop, however there exists a substantial
amount of desktop-specific features (including extensions) which will require a non-trivial
amount of work to integrate with bfcache.
For now, focusing on mobile, as the ratio of history navigations is substantially higher (~20% on
Android vs ~7% on desktop) and the benefit of having back/forward cache on mobile is
substantially higher.

Chrome will give an update when there is a timeline for enabling back/forward cache on
desktop.

WebView support
Chrome is not planning to enable back/forward cache for Android WebView due to associated
complexities.

You might also like