Wykrywanie początkowego stanu widoczności

Ustalenie, czy strona została początkowo wczytana w tle (np. otwarta w nowej karcie w tle), ma kluczowe znaczenie dla dokładnego monitorowania wydajności. Strony wczytywane w tle często mają opóźnione renderowanie i dłuższy czas wskaźników (np. pierwsze wyrenderowanie treści). Zidentyfikowanie tych stron umożliwia odfiltrowanie ich z analizy skuteczności, aby uniknąć zniekształcenia danych.

Najdokładniejszym sposobem pomiaru jest użycie interfejsu API VisibilityStateEntry, który niezawodnie rejestruje zmiany widoczności na osi czasu wydajności przeglądarki, niezależnie od tego, kiedy skrypt jest faktycznie wykonywany.

Wykrywanie początkowej widoczności i czasu działania w tle

OBOWIĄZKOWO: użyj performance.getEntriesByType('visibility-state'), aby uzyskać dostęp do dokładnej historii widoczności. Nie polegaj wyłącznie na sprawdzaniu document.visibilityState w czasie wykonywania, ponieważ jest to podatne na sytuacje wyścigu.

/**
 * 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
    };
  }
}

Strategie zastępcze

W nieobsługiwanych środowiskach możesz sprawdzić właściwość document.visibilityState lub nasłuchiwać zdarzenia visibilitychange.

OBOWIĄZKOWO: musisz zrozumieć, że to podejście zastępcze jest często bardzo niedokładne w określaniu początkowego stanu tła. Skrypty mogą się wczytywać i wykonywać asynchronicznie, więc strona może zostać otwarta w karcie w tle, a następnie przeniesiona przez użytkownika na pierwszy plan, zanim skrypt zostanie pobrany i wykonany. Gdy skrypt w końcu się uruchomi, document.visibilityState będzie synchronicznie odczytywane jako 'visible' i błędnie założysz, że strona została załadowana na pierwszym planie, całkowicie pomijając jej początkowy stan ukryty. Ponadto sygnatura czasowa kreacji zastępczej nie ma wewnętrznej precyzji interfejsu Performance API. Jeśli precyzja jest dla Ciebie priorytetem, nie używaj wartości zastępczej.

/**
 * 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();
}