만족
[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/
물론 무조건 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 관련 이슈가 있다