I spent weeks finding a way to refresh a page or a tab from the server once a user starts or restarts the browser. I was very surprised to find nothing about this topic.
Let's dig into the context, tries and the solution I came up with.
Typically, once a user opens a browser and gets to a page, it directly provides the page in cache without refreshing any data from the server. Obviously, this only applies if the user is not in a private navigation.
In this case, as a user, I always need to open the browser and then manually reload the page to get the last updated data. What? Am I too lazy? Sure I am a developer!
My goal was to detect when the browser launches and automatically refresh the page or the tab at this moment so end users do not need to manually reload the page and updated data immediately come to their eyes! Sounds nice!
As I am using a Service Worker that in my case handles expired pages and refreshing data (requesting data from the server if a page expired), I noticed the navigation through the browser was always in a back forward
state when loading the page after browser launch and actually bypassed the Service Worker to return the page from cache. No way!
Here are the solutions I tried:
- set
Cache-Control
header tono-cache, max-age=0, must-revalidate
for all my pseudo-dynamic pages so it will force the browser to automatically refresh them. My Service Worker was in charge to set this header so my assets still were cached in my CDN. It was okay because my Service Worker was handling these pages based on an expiration date so they still were put in cache based on this date. But it did not work, once the browser launched and and I accessed the page, it still was outdated data loaded from cache; - detect when a tab becomes active to reload the page using tabs API but I found nothing really useful;
- use localStorage API in combination with page Visibility API to store when users first loaded the page, detect when they left the page and reload it when the page becomes visible after a certain minimum amount of time (saying 10 minutes for an example). No way to make it worked at browser launch, it only automatically refreshed the page when the user was getting back to the tab passing 10 minutes (not so bad, but was not my use case).
I still was unable to detect browser launch in my JavaScript.
I finally came up with a solution using Performance and PerformanceNavigationTiming Level 2 APIs.
PerformanceNavigationTiming Level 2 API is still at a Working Draft
status which means this solution is using an experimental technology. Please use with caution.
Browser compatibility is not as bad as expected for an experimental feature. Only Safari, iOS Safari and IE are not supported the solution.
API | Chrome | Edge | Firefox | IE | Opera | Safari | WebView Android | Chrome Android | Firefox Android | Opera Android | iOS Safari | Samsung Internet |
---|---|---|---|---|---|---|---|---|---|---|---|---|
Performance | 6 | 12 | 7 | 9 | 15 | 8 | <=37 | 18 | 7 | 14 | 9 | 1.0 |
Performance.getEntriesByType | 28 | 12 | 35 | 10 | 15 | 11 | <=37 | 28 | 35 | 15 | 11 | 1.5 |
PerformanceNavigationTiming | 57 | 12 | 58 | No | 44 | No | 57 | 57 | 58 | 43 | No | 7.0 |
PerformanceNavigationTiming.type | 57 | 12 | 58 | No | 44 | No | 57 | 57 | 58 | 43 | No | 7.0 |
PerformanceNavigationTiming.unloadEventStart | 57 | 12 | 58 | No | 44 | No | 57 | 57 | 58 | 43 | No | 7.0 |
if ('performance' in window) {
const navigationLastEntry = performance.getEntriesByType('navigation').pop();
if (navigationLastEntry
&& navigationLastEntry.type === 'back_forward'
&& navigationLastEntry.unloadEventStart === 0) {
window.location.reload(true);
}
}
This code does not need the DOM or the page to be loaded to be used. Actually it should be executed before these events are fired.
I typically put this code at the first lines of my index.js
file, outside DOMContentLoaded
event, but you could use it in the head section of your document. Personally speaking, it reloads really fast the page even though used in the index.js
referenced at the end of my HTML files. Adapt to your need.
First the code checks Performance API is supported by the browser.
It then get the last navigation entry.
Finally it will reload the page only if:
- there is a last navigation entry;
- the type of navigation is
back_forward
; - the time immediately before the user agent starts the unload event of the previous document (
unloadEventStart
) equals0
which means there is no previous document.
Please note that the navigation is through the browser's history traversal operation back_forward
when:
- users press
Previous
/Next
buttons in the browser; - users press
Previous
/Next
buttons on their keyboard; - users start or restart the browser and get to the page or tab.
These 3 conditions all put together allow us to detect when the browser loads the page or tab after and only after the browser has launched. Any other back_forward
navigations won’t make the page to reload.
Finally calling window.location.reload()
with true
option indicates the page will reload from the server, false
or no argument to reload from cache.
That’s it! At the end of the day that was a quite simple solution!
As I am more of a back-end developer, please let me know if something's wrong or feel free to contribute if you have an alternative or better solution.
Thanks,
Adrien
Thank you very much, Adrien! This was exactly what I was searching for - great solution.