만족

[Web] 뒤로/앞으로 캐시 (back/forward cache, bfcache) 본문

[Web] 뒤로/앞으로 캐시 (back/forward cache, bfcache)

카테고리 없음 Satisfaction 2023. 1. 14. 19:33

웹 개발을 하다보면 특이한 경험을 한 적이 있을 것이다.

 

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <h1 id="quiz">김흥국이 나온 대학교는?</h1>
    <a href="https://www.google.com">구글로 이동</a>
  </body>
  <script>
    setTimeout(() => {
      document.getElementById("quiz").innerText = "으아 들이대 ㅋㅋ";
    }, 3000);
  </script>
</html>

예를 들어, 이 코드에서는 처음에 '김흥국이 나온 대학교는?' 이 표시되고

3초 뒤 '으아 들이대 ㅋㅋ'가 표시된다.

 

ㅋㅋㅋ

 

그렇다면 다른 페이지로 이동한 다음 뒤로가기로 페이지로 돌아오면 어떻게 될까?

 

여전히 '김흥국이 나온 대학교는' 이 표시되고 3초 뒤 '으아 들이대 ㅋㅋ'가 표시될까?

 

로딩도 없이 바로 '으아 들이대 ㅋㅋ'가 표시된다.

 

어떻게 된 일일까

bfcache(back/forward cache)가 작동했기 때문이다.

 

브라우저에서는 조건에 맞으면 페이지를 벗어나기 전에 memory snapshot을 찍어두고,

다시 돌아왔을 경우 이를 복원해 사용자에게 표시한다.

 

리소스를 다시 다운로드하고, 스크립트를 처음부터 다시 실행하는 것이 아니라

나가기 전 메모리 상태를 그대로 보관한 다음 돌아왔을 때 복원시키기 때문에

즉시 로딩이 완료되고 스크립트도 이전 상태부터 이어서 진행한다.

 

https://web.dev/i18n/ko/bfcache/

 

캐시 뒤로/앞으로

브라우저의 뒤로 및 앞으로 버튼을 사용할 때 페이지를 즉시 로드하도록 최적화하는 방법을 알아보세요.

web.dev

 

물론 무조건 bfcache가 작동하는 것은 아니고, 특정 조건에 부합하는 경우에만 bfcache에 저장/복원된다.

 

아닌 경우도 있다

 

우와 동일한 html을 사용했을 때,

이번에는 구글로 나왔다 돌아왔을 때 다시 '김흥국이 나온 대학교는?' 이 표시되고 3초 뒤 변경된다.

 

무슨 차이가 있을까?

 

여기에서는 응답 헤더의 Cache-Control에 no-store를 추가했다.

 

Cache-Control에 no-store가 포함되어 있는 것은 어떤 방식으로든 캐시하는 것을 금지한다는 것을 의미하므로

bfcache 역시 작동하지 않게 된다.

 

bfcache가 작동하지 않는 경우

다양한 이유가 있지만, 몇 가지 자주 만날 수 있는 이유를 소개한다.

 

1. Cache-control에 no-store가 포함된 경우

2. indexedDB를 사용중인 경우

3. 소켓이 커넥션이 열린 상태인 경우 

4. xhr request 가 진행중인 경우

5. unload 이벤트가 설정된 경우

6. 기타등등...

 

bfcache를 의도적으로 비활성화하려면 손쉽게 unload 이벤트를 등록함으로써 구현할 수 있다.

 

window.addEventListener('unload', ()=>{});

 

그런데 만약 unload 이벤트를 사용해야 하고, bfcache 스펙이 필요하다면

unload 대신 pagehide 이벤트를 사용하면 된다.

 

bfcache로부터 페이지가 복원되었는지 판단하는 방법

pageshow 이벤트를 등록하고, 그 이벤트의 매개변수로 주어지는 값으로 판별할 수 있다.

 

window.addEventListener('pageshow', (e)=>{
  if(e.persisted){
    //bfcache로부터 페이지 복원됨
  }else{
    //bfcache로부터 페이지 복원되지 않음
  }
});

 

이 이벤트를 활용해 bfcache로부터 페이지가 복원되었을 때 갱신해야 할 정보가 있다면 갱신할 수 있다.

 

단, e.persisted === true 일 때 pageshow 내에서 network request를 한다면

해당 요청이 비정상 작동하여 network timeout 을 하는 경우가 있다.

 

따라서 network request를 해야 한다면 다음과 같이 사용한다.

 

window.addEventListener('pageshow', (e)=>{
  if(e.persisted){
    //bfcache로부터 페이지 복원됨
    setTimeout(()=>{
      //네트워크 요청
      fetch('http://your_api_host/path').then(...);
    });
  }else{
    //bfcache로부터 페이지 복원되지 않음
  }
});

이렇게 하면 정상적으로 네트워크 요청-응답을 수행할 수 있다.

 

bfcache가 사용 가능한지 확인하기

 

개발자 도구> 애플리케이션> 뒤로/앞으로 캐시에서 확인할 수 있다.

 

만약 사용 불가능할 경우 왜 불가능한지 이유도 표시되므로,

필요한 경우 사유를 확인하고 수정할 수 있다.

 

주의사항

1. Android Webview에서는 bfcache가 아예 작동하지 않는다

- 공식 문서에서도 지원하지 않는다고 적혀 있다

 

2. safari에서는 가끔 pageshow 이벤트가 아예 호출되지 않는 케이스가 있다

- 다른 이벤트를 이용하거나 로직을 사용하는 등 우회해서 해결한다

 

3. nextjs를 사용하여 개발 시 router 관련 이슈가 있다

- 참고: https://satisfactoryplace.tistory.com/381

 

[Nextjs] bfcache로 페이지가 복원되었을 때 브라우저에 따라 라우터가 업데이트되거나 업데이트되

//... const router= useRouter(); useEffect(()=>{ //... }, [router]); //... 이런 코드가 있을 때, bfcache로부터 페이지가 복원된다면 어떻게 될 것 같은가? 내 생각에는 당연히 memory snapshot을 복구했으니 router가 업

satisfactoryplace.tistory.com



Comments