브라우저의 뒤로 버튼과 앞으로 버튼을 사용할 때 페이지가 즉시 로드되도록 최적화하세요.
뒤로-앞으로 캐시 (또는 bfcache)는 즉각적인 뒤로/앞으로 탐색을 사용 설정하는 브라우저 최적화입니다. 이렇게 하면 사용자, 특히 네트워크나 기기가 느린 사용자의 탐색 환경이 크게 개선됩니다.
웹 개발자는 사용자가 이점을 누릴 수 있도록 모든 브라우저에서 bfcache의 페이지를 최적화하는 방법을 이해하는 것이 중요합니다.
브라우저 호환성
bfcache는 수년 동안 데스크톱과 모바일을 통해 Firefox와 Safari에서 모두 지원되었습니다.
Chrome은 버전 86부터 일부 사용자를 대상으로 Android의 크로스 사이트 탐색에 bfcache를 사용 설정했습니다. 후속 출시에서는 추가 지원이 천천히 배포됩니다. 버전 96부터 데스크톱과 모바일의 모든 Chrome 사용자에게 bfcache가 사용 설정됩니다.
bfcache 기본사항
bfcache는 사용자가 다른 페이지로 이동할 때 페이지의 전체 스냅샷(자바스크립트 힙 포함)을 저장하는 메모리 내 캐시입니다. 메모리에 전체 페이지가 있으므로 사용자가 다시 돌아오기로 하면 브라우저에서 빠르고 쉽게 페이지를 복원할 수 있습니다.
웹사이트를 방문하고 링크를 클릭하여 다른 페이지로 이동하는 몇 번이나 원하는 것이 아니라는 것을 깨닫고 뒤로 버튼을 클릭했나요? 이때 bfcache를 통해 이전 페이지의 로드 속도가 크게 달라집니다.
bfcache가 사용 설정되지 않은 | 이전 페이지를 로드하기 위한 새 요청이 시작되고, 반복 방문에 대해 페이지가 얼마나 최적화되었는지에 따라 브라우저에서 방금 다운로드한 일부 또는 전체 리소스를 다시 다운로드하고 파싱한 후 다시 실행해야 할 수 있습니다. |
bfcache가 사용 설정된 경우 | 네트워크로 전혀 이동할 필요 없이 메모리에서 전체 페이지를 복원할 수 있으므로 이전 페이지는 기본적으로 즉시 로드됩니다. |
다음 동영상에서 bfcache의 작동 방식을 확인하여 탐색 속도를 높일 수 있는지 알아보세요.
위 동영상에서 bfcache를 사용한 예시가 없는 예시보다 훨씬 빠릅니다.
bfcache를 사용하면 탐색 속도가 향상될 뿐만 아니라 리소스를 다시 다운로드할 필요가 없으므로 데이터 사용량도 줄어듭니다.
Chrome 사용 데이터에 따르면 데스크톱 탐색 10개 중 1개, 모바일 탐색 탐색 5개 중 1개는 뒤로 또는 앞으로입니다. bfcache를 사용 설정하면 브라우저에서 매일 수십억 개의 웹페이지를 로드하는 데 걸리는 시간과 데이터 전송을 없앨 수 있습니다.
'캐시'의 작동 방식
bfcache에서 사용하는 '캐시'는 HTTP 캐시와 다릅니다(반복 탐색의 속도를 높이는 데도 유용함). bfcache는 메모리에 있는 전체 페이지의 스냅샷 (자바스크립트 힙 포함)이지만, HTTP 캐시에는 이전에 실행한 요청의 응답만 포함되어 있습니다. 페이지를 로드하는 데 필요한 모든 요청을 HTTP 캐시에서 처리하는 경우는 매우 드물기 때문에 bfcache 복원을 사용한 반복 방문은 가장 잘 최적화된 비 bfcache 탐색보다 항상 더 빠릅니다.
그러나 메모리에 있는 페이지의 스냅샷을 만들려면 진행 중인 코드를 보존하는 최선의 방법이 몇 가지 복잡합니다. 예를 들어 페이지가 bfcache에 있는 상태에서 제한 시간에 도달하는 setTimeout()
호출을 어떻게 처리해야 할까요?
답은 브라우저가 대기 중인 타이머나 해결되지 않은 프러미스(기본적으로 자바스크립트 작업 대기열에 있는 모든 대기 중인 작업) 실행을 일시중지하고 페이지가 bfcache에서 복원될 때(또는 이러한 경우) 처리 작업을 재개하는 것입니다.
어떤 경우에는 시간 제한 또는 프로미스와 같이 상당히 위험성이 낮지만, 다른 경우에는 매우 혼란스럽거나 예기치 않은 동작으로 이어질 수도 있습니다. 예를 들어 브라우저가 IndexedDB 트랜잭션의 일부로 필요한 태스크를 일시중지하면 동일한 출처의 다른 열린 탭에 영향을 미칠 수 있습니다. 동일한 IndexedDB 데이터베이스에 동시에 여러 탭이 액세스할 수 있기 때문입니다. 따라서 일반적으로 브라우저는 IndexedDB 트랜잭션 중에 페이지를 캐시하거나 다른 페이지에 영향을 줄 수 있는 API를 사용하지 않습니다.
다양한 API 사용이 페이지의 bfcache 자격요건에 미치는 영향에 관한 자세한 내용은 아래 bfcache의 페이지 최적화를 참고하세요.
bfcache 및 단일 페이지 앱 (SPA)
bfcache는 브라우저에서 관리하는 탐색과 함께 작동합니다. 따라서 SPA 내 소위 '소프트 내비게이션'과는 호환되지 않지만 SPA의 가장 큰 장점 중 하나는 그러한 탐색 유형이 어쨌든 빨라야 한다는 점입니다. 하지만 SPA로 돌아가는 경우에는 처음부터 앱을 완전히 다시 초기화하는 것보다 bfcache를 확실히 도움이 될 수 있습니다.
bfcache를 관찰하는 API
bfcache는 브라우저에서 자동으로 실행하는 최적화지만 개발자가 페이지를 최적화하고 그에 따라 모든 측정항목 또는 성능 측정을 조정할 수 있도록 발생 시점을 파악하는 것은 여전히 중요합니다.
bfcache를 관찰하는 데 사용되는 기본 이벤트는 페이지 전환 이벤트(pageshow
및 pagehide
)입니다. 이 이벤트는 bfcache와 같은 기간 동안 사용된 것으로 현재 사용되는 모든 브라우저에서 지원됩니다.
최신 페이지 수명 주기 이벤트(freeze
및 resume
)는 페이지가 bfcache에 들어가거나 나올 때뿐만 아니라 일부 다른 상황에서도 전달됩니다. CPU 사용량을 최소화하기 위해 백그라운드 탭이 멈추는 경우를 예로 들 수 있습니다. 페이지 수명 주기 이벤트는 현재 Chromium 기반 브라우저에서만 지원됩니다.
페이지가 bfcache에서 복원되는 시점 관찰
pageshow
이벤트는 페이지가 처음 로드될 때 그리고 페이지가 bfcache에서 복원될 때마다 load
이벤트 직후에 실행됩니다. pageshow
이벤트에는 페이지가 bfcache에서 복원되면 true
이고 복원되지 않은 경우 false
인 persisted
속성이 있습니다. persisted
속성을 사용하여 일반 페이지 로드와 bfcache 복원을 구분할 수 있습니다. 예를 들면 다음과 같습니다.
window.addEventListener('pageshow', (event) => {
if (event.persisted) {
console.log('This page was restored from the bfcache.');
} else {
console.log('This page was loaded normally.');
}
});
Page Lifecycle API를 지원하는 브라우저에서는 페이지가 bfcache에서 복원될 때 (pageshow
이벤트 직전)에도 resume
이벤트가 실행되지만 사용자가 정지된 백그라운드 탭을 다시 방문하는 경우에도 실행됩니다.
페이지가 고정된 후 (bfcache의 페이지 포함) 상태를 업데이트하려면 resume
이벤트를 사용하면 됩니다. 하지만 사이트의 bfcache 적중률을 측정하려면 pageshow
이벤트를 사용해야 합니다. 경우에 따라서는 둘 다 사용해야 할 수도 있습니다.
페이지가 bfcache에 진입하는 시점 관찰
pagehide
이벤트는 pageshow
이벤트에 대응됩니다. pageshow
이벤트는 페이지가 정상적으로 로드되거나 bfcache에서 복원될 때 실행됩니다.
pagehide
이벤트는 페이지가 정상적으로 로드 해제되거나 브라우저에서 bfcache에 넣으려고 할 때 실행됩니다.
pagehide
이벤트에는 persisted
속성도 있습니다. false
이면 페이지가 bfcache에 들어가지 않을 것임을 확신할 수 있습니다. 하지만 persisted
속성이 true
라고 해서 페이지가 캐시된다는 보장은 없습니다.
브라우저가 페이지를 캐시intends 하지만 캐시할 수 없는 요인이 있을 수 있습니다.
window.addEventListener('pagehide', (event) => {
if (event.persisted) {
console.log('This page *might* be entering the bfcache.');
} else {
console.log('This page will unload normally and be discarded.');
}
});
마찬가지로 freeze
이벤트는 pagehide
이벤트 직후에 실행되지만(이벤트의 persisted
속성이 true
인 경우) 다시 말해 브라우저에서 페이지를 캐시intends한다는 의미일 뿐입니다. 아래에 설명된 여러 가지 이유로 여전히 삭제해야 할 수 있습니다.
bfcache에 관한 페이지 최적화
모든 페이지가 bfcache에 저장되는 것은 아니며, 페이지가 bfcache에 저장되더라도 계속해서 저장되지는 않습니다. 캐시 적중률을 최대화하기 위해서는 개발자가 페이지에서 bfcache를 사용할 수 있는 (또는 사용할 수 없는) 이유를 이해하는 것이 중요합니다.
다음 섹션에서는 브라우저에서 페이지를 캐시할 수 있는 확률을 극대화하기 위한 권장사항을 간략하게 설명합니다.
unload
이벤트 사용 안함
모든 브라우저에서 bfcache에 맞게 최적화하는 가장 중요한 방법은 unload
이벤트를 절대 사용하지 않는 것입니다. 단 한 건도 없었습니다.
unload
이벤트는 bfcache보다 먼저 발생하고 인터넷의 많은 페이지가 unload
이벤트가 실행된 후 페이지가 계속 존재하지 않을 것이라는 (합리적인) 가정하에 작동하므로 브라우저에 문제가 됩니다. 이러한 페이지 중 상당수가 사용자가 페이지에서 나갈 때마다 unload
이벤트가 발생할 것이라는 가정으로 또한 빌드되었기 때문에 문제가 될 수 있습니다. 이는 더 이상 유효하지 않으며 오랫동안 적용되지 않았던 것입니다.
브라우저는 딜레마에 직면해 사용자 환경을 개선할 수 있지만 페이지가 손상될 위험이 있는 방법 중에서 선택해야 합니다.
데스크톱에서 Chrome 및 Firefox는 unload
리스너를 추가하면 페이지에서 bfcache를 사용할 수 없도록 했습니다. 이는 위험은 적지만 많은 페이지의 자격을 박탈하기도 합니다. Safari는 unload
이벤트 리스너로 일부 페이지를 캐시하려고 시도하지만 중단 가능성을 줄이기 위해 사용자가 다른 곳을 탐색할 때 unload
이벤트를 실행하지 않으므로 이벤트가 매우 불안정해집니다.
모바일에서는 unload
이벤트가 항상 매우 불안정했기 때문에 모바일에서 Chrome 및 Safari는 unload
이벤트 리스너로 페이지를 캐시하려고 시도합니다. Firefox는 unload
를 사용하는 페이지를 bfcache의 대상이 아닌 것으로 취급합니다. 단, iOS는 예외로, 모든 브라우저에서 WebKit 렌더링 엔진을 사용해야 하므로 Safari처럼 작동합니다.
unload
이벤트를 사용하는 대신 pagehide
이벤트를 사용합니다. pagehide
이벤트는 현재 unload
이벤트가 발생하는 모든 경우에 실행되며 또한 페이지가 bfcache에 배치될 때도 실행됩니다.
실제로 Lighthouse에는 no-unload-listeners
감사가 있습니다. 이 감사는 페이지에 있는 JavaScript (서드 파티 라이브러리의 JavaScript 포함)가 unload
이벤트 리스너를 추가하면 개발자에게 경고를 보냅니다.
bfcache의 안정성과 성능에 미치는 영향으로 인해 Chrome에서 unload
이벤트를 지원 중단할 계획입니다.
권한 정책을 사용하여 페이지에서 로드 취소 핸들러가 사용되지 않도록 방지
unload
이벤트 핸들러를 사용하지 않는 사이트는 Chrome 115의 권한 정책을 사용하여 이벤트 핸들러가 추가되지 않도록 할 수 있습니다.
Permission-Policy: unload()
이렇게 하면 로드 취소 핸들러를 추가하여 사이트에서 bfcache를 사용할 수 없게 되어 서드 파티 또는 확장 프로그램이 사이트 속도를 저하하는 것을 방지할 수 있습니다.
beforeunload
리스너는 조건부로만 추가
beforeunload
이벤트로 인해 최신 브라우저 bfcache에서 페이지에서 bfcache를 사용할 수 없지만 이전에는 bfcache를 사용할 수 없었기 때문에 여전히 불안정하므로 꼭 필요한 경우가 아니면 사용하지 마세요.
그러나 unload
이벤트와 달리 beforeunload
를 적법하게 사용할 수 있습니다. 예를 들어 변경사항을 저장하지 않았음을 사용자에게 경고하려는 경우
페이지를 나가면 변경사항을 잃게 됩니다. 이 경우에는 사용자에게 저장되지 않은 변경사항이 있을 때만 beforeunload
리스너를 추가한 다음, 저장되지 않은 변경사항이 저장된 직후에 삭제하는 것이 좋습니다.
window.addEventListener('beforeunload', (event) => { if (pageHasUnsavedChanges()) { event.preventDefault(); return event.returnValue = 'Are you sure you want to exit?'; } });
function beforeUnloadListener(event) { event.preventDefault(); return event.returnValue = 'Are you sure you want to exit?'; }; // A function that invokes a callback when the page has unsaved changes. onPageHasUnsavedChanges(() => { window.addEventListener('beforeunload', beforeUnloadListener); }); // A function that invokes a callback when the page's unsaved changes are resolved. onAllChangesSaved(() => { window.removeEventListener('beforeunload', beforeUnloadListener); });
Cache-Control: no-store
사용 최소화
Cache-Control: no-store
는 응답에 설정할 수 있는 HTTP 헤더 웹 서버로, 응답을 HTTP 캐시에 저장하지 않도록 브라우저에 지시합니다. 로그인이 필요한 페이지와 같이 민감한 사용자 정보가 포함된 리소스에 사용해야 합니다.
bfcache는 HTTP 캐시는 아니지만, 지금까지 Cache-Control: no-store
가 페이지 리소스 (하위 리소스가 아님)에 설정되면 브라우저는 페이지를 bfcache에 저장하지 않도록 선택했습니다. 개인 정보를 보호하는 방식으로 Chrome에서 이 동작을 변경하기 위한 작업이 진행 중이지만 현재 Cache-Control: no-store
를 사용하는 페이지에서는 bfcache를 사용할 수 없습니다.
Cache-Control: no-store
는 페이지의 bfcache 사용을 제한하므로 모든 종류의 캐싱이 적절하지 않은 민감한 정보가 포함된 페이지에만 설정해야 합니다.
항상 최신 콘텐츠를 제공하려고 하고 콘텐츠에 민감한 정보가 포함되어 있지 않은 페이지에는 Cache-Control: no-cache
또는 Cache-Control: max-age=0
를 사용합니다. 이 지시어는 콘텐츠를 제공하기 전에 브라우저에게 콘텐츠를 재검증하도록 지시하며, 페이지의 bfcache 적합성에 영향을 미치지 않습니다.
페이지가 bfcache에서 복원되면 HTTP 캐시가 아닌 메모리에서 복원됩니다. 따라서 Cache-Control: no-cache
또는 Cache-Control: max-age=0
와 같은 지시어는 고려되지 않으며 콘텐츠가 사용자에게 표시되기 전에 유효성 재검사가 수행되지 않습니다.
하지만 bfcache 복원이 즉시 이루어지고 페이지가 bfcache에 아주 오래 머무르지 않기 때문에 콘텐츠가 오래되었을 가능성은 낮기 때문에 여전히 더 나은 사용자 환경일 수 있습니다. 그러나 콘텐츠가 분 단위로 변경되는 경우 다음 섹션에 설명된 대로 pageshow
이벤트를 사용하여 업데이트를 가져올 수 있습니다.
bfcache 복원 후 오래된 데이터 또는 민감한 정보 업데이트
사이트에서 사용자 상태(특히 모든 민감한 사용자 정보)를 유지하는 경우 페이지가 bfcache에서 복원된 후 해당 데이터를 업데이트하거나 삭제해야 합니다.
예를 들어 사용자가 결제 페이지로 이동한 후 장바구니를 업데이트하는 경우 오래된 페이지가 bfcache에서 복원되면 뒤로 탐색에 오래된 정보가 노출될 수 있습니다.
또 다른 중요한 예는 사용자가 공용 컴퓨터의 사이트에서 로그아웃하고 다음 사용자가 뒤로 버튼을 클릭하는 경우입니다. 이로 인해 사용자가 로그아웃할 때 삭제되었다고 가정한 비공개 데이터가 노출될 수 있습니다.
이러한 상황을 방지하려면 event.persisted
가 true
인 경우 pageshow
이벤트 후에 항상 페이지를 업데이트하는 것이 좋습니다.
window.addEventListener('pageshow', (event) => {
if (event.persisted) {
// Do any checks and updates to the page
}
});
콘텐츠를 제자리에서 업데이트하는 것이 이상적이지만 일부 변경사항의 경우 강제로 완전히 새로고침해야 할 수도 있습니다. 다음 코드는 pageshow
이벤트에 사이트별 쿠키가 있는지 확인하고 쿠키를 찾을 수 없으면 새로고침합니다.
window.addEventListener('pageshow', (event) => {
if (event.persisted && !document.cookie.match(/my-cookie/)) {
// Force a reload if the user has logged out.
location.reload();
}
});
새로고침은 앞으로 탐색을 허용하기 위해 기록이 계속 보존된다는 이점이 있지만 경우에 따라 리디렉션이 더 적합할 수 있습니다.
광고 및 bfcache 복원
각 뒤로-앞으로 탐색에서 새로운 광고 세트를 게재하기 위해 bfcache를 사용하지 않고 싶을 수 있습니다. 그러나 이러한 행동이 실적에 영향을 줄 뿐 아니라 광고 참여 향상으로 이어지는지도 의문이 있습니다. 사용자가 클릭할 수 없는 bfcache에서 복원하는 대신 새로고침하여 다시 클릭해 보려는 광고를 발견했을 수 있습니다. 가정을 하기 전에 이 시나리오를 A/B 테스트로 테스트하는 것이 좋습니다.
bfcache 복원 시 광고를 새로고침하려는 사이트의 경우 event.persisted
가 true
일 때 pageshow
이벤트의 광고만 새로고침하면 페이지 성능에 영향을 미치지 않고 새로고침할 수 있습니다. 광고 제공업체에 문의하세요. Google 게시 태그를 사용하여 이 작업을 실행하는 방법의 한 가지 예를 참고하세요.
window.opener
참조 피하기
이전 브라우저에서 rel="noopener"
를 지정하지 않고 target=_blank
를 사용한 링크에서 window.open()
를 사용하여 페이지를 연 경우 여는 페이지는 열린 페이지의 창 객체에 관한 참조를 갖습니다.
null이 아닌 window.opener
참조가 포함된 페이지는 보안 위험일 뿐만 아니라 bfcache에 액세스하려는 페이지가 손상될 수 있으므로 bfcache에 안전하게 저장할 수 없습니다.
따라서 window.opener
참조는 만들지 않는 것이 좋습니다. 가능한 경우 rel="noopener"
를 사용하면 됩니다. 참고로, 이는 현재 모든 최신 브라우저에서 기본값입니다. 사이트에서 창을 열고 window.postMessage()
를 통해 제어하거나 창 객체를 직접 참조해야 하는 경우 열린 창과 오프너 모두 bfcache를 사용할 수 없습니다.
사용자가 다른 곳을 나가기 전에 열려 있는 연결을 항상 종료
위에서 언급했듯이 페이지가 bfcache에 배치되면 모든 예약된 JavaScript 작업이 일시중지되었다가 페이지가 캐시에서 삭제될 때 다시 시작됩니다.
이러한 예약된 JavaScript 작업이 DOM API(또는 현재 페이지로만 격리된 다른 API)에만 액세스하는 경우 페이지가 사용자에게 표시되지 않을 때 이 작업을 일시중지해도 문제가 발생하지 않습니다.
그러나 이러한 작업이 동일한 출처의 다른 페이지 (예: IndexedDB, Web Locks, WebSockets 등)에서도 액세스할 수 있는 API에 연결된 경우 이러한 작업을 일시중지하면 다른 탭의 코드가 실행되지 않을 수 있으므로 문제가 될 수 있습니다.
따라서 일부 브라우저는 다음과 같은 시나리오에서 bfcache에 페이지를 넣으려고 하지 않습니다.
- 열려 있는 IndexedDB 연결이 있는 페이지
- fetch() 또는 XMLHttpRequest가 진행 중인 페이지
- 열려 있는 WebSocket 또는 WebRTC 연결이 있는 페이지
페이지에서 이러한 API를 사용하는 경우 pagehide
또는 freeze
이벤트 중에 항상 연결을 닫고 관찰자를 삭제하거나 연결 해제하는 것이 좋습니다. 이렇게 하면 브라우저가 다른 열린 탭에 영향을 미칠 위험 없이 페이지를 안전하게 캐시할 수 있습니다.
그런 다음 페이지가 bfcache에서 복원되면 pageshow
또는 resume
이벤트에서 이러한 API를 다시 열거나 연결할 수 있습니다.
다음 예에서는 pagehide
이벤트 리스너에서 열려 있는 연결을 닫아 IndexedDB를 사용할 때 페이지에 bfcache를 허용하는 방법을 보여줍니다.
let dbPromise;
function openDB() {
if (!dbPromise) {
dbPromise = new Promise((resolve, reject) => {
const req = indexedDB.open('my-db', 1);
req.onupgradeneeded = () => req.result.createObjectStore('keyval');
req.onerror = () => reject(req.error);
req.onsuccess = () => resolve(req.result);
});
}
return dbPromise;
}
// Close the connection to the database when the user is leaving.
window.addEventListener('pagehide', () => {
if (dbPromise) {
dbPromise.then(db => db.close());
dbPromise = null;
}
});
// Open the connection when the page is loaded or restored from bfcache.
window.addEventListener('pageshow', () => openDB());
페이지를 캐시할 수 있는지 테스트하기
Chrome DevTools를 사용하면 페이지가 bfcache에 최적화되어 있는지 테스트하고 bfcache 사용을 막는 문제를 식별할 수 있습니다.
특정 페이지를 테스트하려면 Chrome에서 해당 페이지로 이동한 다음 DevTools에서 애플리케이션 > 뒤로-앞으로 캐시로 이동합니다. 그런 다음 Run Test 버튼을 클릭하면 DevTools가 bfcache에서 페이지를 복원할 수 있는지 판단하기 위해 페이지에서 나갔다가 다시 이동합니다.
성공하면 패널에 '뒤로-앞으로 캐시에서 복원됨'이 표시됩니다.
실패하면 패널에 페이지가 복원되지 않았다는 메시지와 함께 그 이유가 표시됩니다.
개발자가 해결할 수 있는 문제인 경우 다음과 같이 표시됩니다.
위 스크린샷에서 unload
이벤트 리스너를 사용하면 페이지에서 bfcache를 사용할 수 없습니다. unload
에서 pagehide
를 대신 사용하도록 전환하여 이 문제를 해결할 수 있습니다.
window.addEventListener('unload', ...);
window.addEventListener('pagehide', ...);
또한 Lighthouse 10.0에는 bfcache 감사가 추가되어 DevTools와 유사한 테스트를 수행하고 감사에 실패하면 페이지를 사용할 수 없는 이유도 제공합니다. 자세한 내용은 bfcache 감사 문서를 참고하세요.
bfcache가 분석 및 성능 측정에 미치는 영향
애널리틱스 도구로 사이트 방문을 추적하는 경우 Chrome에서 더 많은 사용자에게 bfcache를 계속 사용 설정함에 따라 보고되는 총 페이지 조회수가 감소할 수 있습니다.
실제로 대부분의 인기 분석 라이브러리에서 bfcache 복원을 새 페이지 조회수로 추적하지 않기 때문에 이미 bfcache를 구현하는 다른 브라우저의 페이지 조회수를 실제보다 적게 보고하고 있을 수 있습니다.
Chrome에서 bfcache를 사용 설정하여 페이지 조회수가 내려가지 않게 하려면 pageshow
이벤트를 수신하고 persisted
속성을 확인하여 bfcache 복원을 페이지 조회수로 보고하면 됩니다 (권장).
다음 예는 Google 애널리틱스로 이 작업을 수행하는 방법을 보여줍니다. 로직은 다른 분석 도구의 경우와 비슷합니다.
// Send a pageview when the page is first loaded.
gtag('event', 'page_view');
window.addEventListener('pageshow', (event) => {
// Send another pageview if the page is restored from bfcache.
if (event.persisted) {
gtag('event', 'page_view');
}
});
bfcache 적중률 측정
또한 bfcache를 활용하지 않는 페이지를 식별하기 위해 bfcache 사용 여부를 추적할 수도 있습니다. 페이지 로드의 탐색 유형을 측정하면 됩니다.
// Send a navigation_type when the page is first loaded.
gtag('event', 'page_view', {
'navigation_type': performance.getEntriesByType('navigation')[0].type;
});
window.addEventListener('pageshow', (event) => {
if (event.persisted) {
// Send another pageview if the page is restored from bfcache.
gtag('event', 'page_view', {
'navigation_type': 'back_forward_cache';
});
}
});
back_forward_cache
에 대한 back_forward
탐색의 비율을 보면 bfcache 비율을 계산할 수 있습니다.
뒤로/앞으로 탐색에서 bfcache를 사용하지 않는 다음과 같은 시나리오는 사이트 소유자가 제어할 수 없는 여러 시나리오가 있다는 사실을 알아야 합니다.
- 사용자가 브라우저를 종료하고 다시 시작할 때
- 사용자가 탭을 복제할 때
- 사용자가 탭을 닫고 닫을 때
이러한 경우 일부 브라우저에서는 원래 탐색 유형이 유지될 수 있으므로 뒤로/앞으로 탐색이 아니더라도 back_forward
유형이 표시될 수 있습니다.
이러한 제외가 없어도 메모리 절약을 위해 일정 기간이 지나면 bfcache가 삭제됩니다.
따라서 웹사이트 소유자는 모든 back_forward
탐색에 100% 의 bfcache 적중률을 기대해서는 안 됩니다. 그러나 비율을 측정하면 페이지 자체로 인해 뒤로 및 앞으로 탐색 비율이 높은 경우 bfcache 사용을 차단하는 페이지를 식별하는 데 유용할 수 있습니다.
Chrome팀은 bfcache가 사용되지 않은 이유를 공개하기 위해 NotRestoredReasons
API를 개발하고 있습니다. 이를 통해 개발자는 캐시가 사용되지 않은 이유를 이해하고 이러한 캐시가 사이트의 개선을 위해 노력할 수 있습니다.
실적 측정
bfcache는 필드에서 수집되는 성능 측정항목, 특히 페이지 로드 시간을 측정하는 측정항목에 부정적인 영향을 미칠 수도 있습니다.
bfcache 탐색은 새 페이지 로드를 시작하지 않고 기존 페이지를 복원하므로 bfcache를 사용 설정하면 수집되는 총 페이지 로드 수가 감소합니다. 하지만 중요한 점은 bfcache 복원으로 대체된 페이지 로드가 데이터 세트에서 가장 빠른 페이지 로드였을 가능성이 높다는 점입니다. 그 이유는 뒤로 및 앞으로 탐색은 정의상 반복 방문이고 반복 페이지 로드는 일반적으로 HTTP 캐싱으로 인해 신규 방문자의 페이지 로드보다 일반적으로 더 빠르기 때문입니다.
그 결과, 데이터 세트의 페이지 로드 속도가 빨라지고 사용자가 경험하는 성능은 향상되었지만 분포가 느려질 수 있습니다.
이 문제를 처리하는 방법에는 여러 가지가 있습니다. 하나는 모든 페이지 로드 측정항목을 각각의 탐색 유형(navigate
, reload
, back_forward
, prerender
)로 주석 처리하는 것입니다. 이렇게 하면 전체 분포가 음수로 편중되더라도 이러한 탐색 유형 내에서 성능을 계속 모니터링할 수 있습니다. 이 방법은 TTFB(첫 바이트까지의 시간)와 같은 사용자 중심이 아닌 페이지 로드 측정항목에 권장됩니다.
코어 웹 바이탈과 같은 사용자 중심 측정항목의 경우 사용자 환경을 더 정확하게 나타내는 값을 보고하는 것이 더 좋습니다.
코어 웹 바이탈에 미치는 영향
코어 웹 바이탈은 다양한 측정기준 (로드 속도, 상호작용성, 시각적 안정성)으로 웹페이지의 사용자 환경을 측정합니다. 사용자가 기존 페이지 로드보다 빠른 탐색으로 bfcache 복원을 경험하므로 코어 웹 바이탈 측정항목에 이를 반영하는 것이 중요합니다. 결국 사용자는 bfcache의 사용 설정 여부는 중요하지 않으며 탐색이 빠를 뿐입니다.
코어 웹 바이탈 측정항목을 수집하고 보고하는 Chrome 사용자 환경 보고서와 같은 도구는 bfcache 복원을 데이터 세트에서 별도의 페이지 방문으로 취급합니다.
bfcache 복원 후 이러한 측정항목을 측정하기 위한 전용 웹 성능 API는 (아직) 없지만, 그 값은 기존 웹 API를 사용하여 근사화할 수 있습니다.
- 콘텐츠가 포함된 최대 페인트(LCP)의 경우
pageshow
이벤트의 타임스탬프와 다음에 페인트된 프레임의 타임스탬프 사이의 델타를 사용할 수 있습니다. 프레임의 모든 요소가 동시에 페인트되기 때문입니다. bfcache 복원의 경우 LCP와 FCP는 동일합니다. - 최초 입력 반응 시간 (FID)의 경우 이벤트 리스너(FID 폴리필에 사용된 것과 동일한)를
pageshow
이벤트 리스너로 다시 추가하고 FID 복원 후 첫 번째 캐시 입력으로 FID를 보고할 수 있습니다. - 누적 레이아웃 변경 (CLS)의 경우 기존 Performance Observer를 계속 사용할 수 있습니다. 현재 CLS 값을 0으로 재설정하기만 하면 됩니다.
bfcache가 각 측정항목에 미치는 영향에 관한 자세한 내용은 개별 코어 웹 바이탈 측정항목 가이드 페이지를 참고하세요. 코드에서 이러한 측정항목의 bfcache 버전을 구현하는 방법에 관한 구체적인 예는 web-vitals JS 라이브러리에 이를 추가하는 PR을 참고하세요.
추가 리소스
- Firefox 캐싱 (Firefox의 bfcache)
- 페이지 캐시 (Safari: bfcache)
- 뒤로-앞으로 캐시: 웹에 노출된 동작 (브라우저 간 bfcache 차이)
- bfcache 테스터 (다양한 API 및 이벤트가 브라우저에서 bfcache에 미치는 영향 테스트)
- 성능 게임 체인저: 브라우저 뒤로/앞으로 캐시 (bfcache를 사용해 극적인 코어 웹 바이탈 개선사항을 보여주는 Smashing Magazine의 우수사례)