Het is essentieel om te bepalen of een pagina in eerste instantie op de achtergrond is geladen (bijvoorbeeld geopend op een nieuw tabblad op de achtergrond) om de prestaties nauwkeurig te kunnen bijhouden. Pagina's die op de achtergrond worden geladen, hebben vaak een vertraagde weergave en langere statistiektijden (zoals First Contentful Paint). Als u deze pagina's herkent, kunt u ze uit de prestatieanalyse filteren om vertekende gegevens te voorkomen.
De meest nauwkeurige manier om dit te meten is met de VisibilityStateEntry API, die betrouwbaar zichtbaarheidswijzigingen registreert op de prestatietijdlijn van de browser, ongeacht wanneer uw script daadwerkelijk wordt uitgevoerd.
Eerste zichtbaarheid en achtergrondtijd detecteren
VERPLICHT: Gebruik performance.getEntriesByType('visibility-state') om de exacte zichtbaarheidsgeschiedenis te openen. Vertrouw niet alleen op de controle van document.visibilityState op het moment van uitvoering, omdat deze gevoelig is voor race-omstandigheden.
/**
* Accurately determines visibility state history using the Performance API.
*/
function getVisibilityInfo() {
// Retrieve VisibilityStateEntry members:
const entries = performance.getEntriesByType('visibility-state');
if (entries.length > 0) {
const firstEntry = entries[0];
// If the first performance entry for visibility is 'hidden',
// the page was loaded in the background.
const initiallyBackgrounded = firstEntry.name === 'hidden';
// Find the precise, high-resolution timestamp of when the page
// was first backgrounded.
let timeBackgrounded = null;
for (const entry of entries) {
if (entry.name === 'hidden') {
// entry.startTime is used because it provides the exact browser
// timestamp of the visibility change, which is required for precision
timeBackgrounded = entry.startTime;
break;
}
}
return {
initiallyBackgrounded,
timeBackgrounded
};
}
}
Reservestrategieën
Voor niet-ondersteunde omgevingen kun je terugvallen op de property document.visibilityState of luisteren naar de gebeurtenis visibilitychange.
VERPLICHT: Je moet begrijpen dat deze fallback-benadering vaak zeer onnauwkeurig is om de oorspronkelijke achtergrondstatus te bepalen. Omdat scripts asynchroon kunnen worden geladen en uitgevoerd, kan een pagina worden geopend op een achtergrondtabblad en daarna door de gebruiker op de voorgrond worden geplaatst voordat het script is gedownload en uitgevoerd. Als je script uiteindelijk wordt uitgevoerd, wordt document.visibilityState synchroon gelezen als 'visible' en ga je er ten onrechte van uit dat de pagina op de voorgrond is geladen, waardoor je de oorspronkelijke verborgen status volledig mist. Bovendien heeft het reserve-tijdstempel niet de interne precisie van de Performance API. Als precisie een hoge prioriteit heeft, gebruik je de fallback niet.
/**
* Fallback implementation using document.visibilityState.
* This approach is prone to race conditions if the script loads asynchronously.
*/
function getFallbackVisibilityInfo() {
// Check the state exactly when this script executes.
// This will fail to detect an initial background state if the user
// foregrounded the page before this script executed.
let initiallyBackgrounded = document.visibilityState === 'hidden';
// If it's hidden now, we approximate that it was hidden from load (time 0).
let timeBackgrounded = initiallyBackgrounded ? 0 : null;
// Listen for future visibility changes to capture if it is backgrounded later.
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden' && timeBackgrounded === null) {
// performance.now() is used here as a fallback, but it only gives
// us the time the event listener fired, not the precise internal
// browser time the visibility actually changed.
timeBackgrounded = performance.now();
}
});
return {
get initiallyBackgrounded() { return initiallyBackgrounded; },
get timeBackgrounded() { return timeBackgrounded; }
};
}
// Modern implementation using VisibilityStateEntry API.
function getVisibilityInfo() {
// Code omitted here would be the same modern
// implementation shown earlier in this guide
// ...
}
// DO: Detect if the VisibilityStateEntry API is available
if ('VisibilityStateEntry' in window) {
// DO: If VisibilityStateEntry is available, use it first:
getVisibilityInfo();
} else {
// DO: If VisibilityStateEntry is unavailable, fall back to `document.visibilityState`:
getFallbackVisibilityInfo();
}