초기 공개 상태 감지

페이지가 처음에 백그라운드에서 로드되었는지 (예: 새 백그라운드 탭에서 열림) 확인하는 것은 정확한 성능 모니터링에 매우 중요합니다. 백그라운드에서 로드된 페이지는 렌더링이 지연되고 측정항목 시간 (예: 첫 콘텐츠 페인트)이 길어지는 경우가 많습니다. 이러한 페이지를 식별하면 실적 분석에서 제외하여 데이터가 왜곡되는 것을 방지할 수 있습니다.

이를 측정하는 가장 정확한 방법은 스크립트가 실제로 실행되는 시점과 관계없이 브라우저의 성능 타임라인에서 공개 상태 변경사항을 안정적으로 기록하는 VisibilityStateEntry API를 사용하는 것입니다.

초기 공개 상태 및 백그라운드 시간 감지

필수: 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();
}