Mendeteksi Status Visibilitas Awal

Menentukan apakah halaman awalnya dimuat di latar belakang (misalnya, dibuka di tab latar belakang baru) sangat penting untuk pemantauan performa yang akurat. Halaman yang dimuat di latar belakang sering kali mengalami penundaan rendering dan waktu metrik yang lebih lama (seperti First Contentful Paint). Dengan mengidentifikasi halaman ini, Anda dapat memfilternya dari analisis performa untuk menghindari data yang tidak akurat.

Cara paling akurat untuk mengukurnya adalah dengan menggunakan VisibilityStateEntry API, yang secara andal mencatat perubahan visibilitas pada linimasa performa browser, terlepas dari kapan skrip Anda benar-benar dijalankan.

Mendeteksi visibilitas awal dan waktu latar belakang

WAJIB: Gunakan performance.getEntriesByType('visibility-state') untuk mengakses histori visibilitas yang tepat. Jangan hanya mengandalkan pemeriksaan document.visibilityState pada waktu eksekusi, karena rentan terhadap kondisi race.

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

Strategi penggantian

Untuk lingkungan yang tidak didukung, Anda dapat kembali memeriksa properti document.visibilityState atau memproses peristiwa visibilitychange.

WAJIB: Anda harus memahami bahwa pendekatan penggantian ini sering kali sangat tidak akurat untuk menentukan status latar belakang awal. Karena skrip dapat dimuat dan dieksekusi secara asinkron, halaman dapat dibuka di tab latar belakang, lalu ditampilkan di latar depan oleh pengguna sebelum skrip Anda selesai didownload dan dieksekusi. Saat skrip Anda akhirnya berjalan, document.visibilityState akan dibaca secara sinkron sebagai 'visible', dan Anda akan salah berasumsi bahwa halaman dimuat di latar depan, sehingga benar-benar melewatkan status tersembunyi awalnya. Selain itu, stempel waktu pengganti tidak memiliki presisi internal Performance API. Jika presisi adalah prioritas tinggi, jangan gunakan penggantian.

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