זיהוי מצב החשיפה הראשוני

כדי לעקוב אחרי הביצועים בצורה מדויקת, חשוב מאוד לדעת אם דף נטען בהתחלה ברקע (למשל, נפתח בכרטיסייה חדשה ברקע). דפים שנטענים ברקע בדרך כלל עוברים רינדור באיחור, וזמני המדדים שלהם ארוכים יותר (כמו הצגת תוכן ראשוני (FCP)). זיהוי הדפים האלה מאפשר לכם לסנן אותם מניתוח הביצועים כדי למנוע הטיה של הנתונים.

הדרך הכי מדויקת למדוד את זה היא באמצעות ה-API של VisibilityStateEntry, שמתעד באופן מהימן שינויים בנראות בציר הזמן של ביצועי הדפדפן, בלי קשר למועד שבו הסקריפט שלכם פועל בפועל.

זיהוי החשיפה הראשונית וזמן הפעולה ברקע

חובה: צריך להשתמש ב-performance.getEntriesByType('visibility-state') כדי לגשת להיסטוריית החשיפה המדויקת. אל תסתמכו רק על בדיקת document.visibilityState בזמן הביצוע, כי היא חשופה למרוץ תהליכים.

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

אסטרטגיות חלופיות

בסביבות לא נתמכות, אפשר לחזור לבדיקת המאפיין document.visibilityState או להאזנה לאירוע visibilitychange.

חובה: חשוב להבין שהגישה החלופית הזו היא בדרך כלל לא מדויקת לקביעת מצב הרקע הראשוני. מכיוון שסקריפטים יכולים להיטען ולפעול באופן אסינכרוני, יכול להיות שהמשתמש יפתח דף בכרטיסייה ברקע ואז יעביר אותה לחזית לפני שהסקריפט יסיים את ההורדה וההפעלה. כשהסקריפט יפעל בסופו של דבר, document.visibilityState יקרא באופן סינכרוני כ-'visible', ותניחו באופן שגוי שהדף נטען בחזית, ותפספסו לחלוטין את המצב המוסתר הראשוני שלו. בנוסף, לחותמת הזמן החלופית אין את הדיוק הפנימי של Performance API. אם הדיוק חשוב לכם, אל תשתמשו בערך החלופי.

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