transferSize가 0인데 캐시 적중이 아닐 수 있는 이유
성능 기록에 transferSize 0이 찍혀 캐시에서 읽은 줄 알았는데, 별도 CDN의 스크립트도 똑같이 0으로 나온다. 진짜 캐시 적중은 어떤 값으로 가려낼 수 있을까?

- transferSize가 0이라는 사실만으로 캐시 적중을 판정할 수 없다.
- Firefox 158도 deliveryType의 cache 값을 지원해 HTTP 캐시 사용을 표시한다.
- 캐시 사용, 서버 재검증, 정보 비공개를 구분해야 성능 지표를 잘못 읽지 않는다.
크기가 숨겨진 CDN 파일도 0으로 보인다
웹페이지의 이미지·스크립트가 캐시에서 왔는지 알아보려고 transferSize === 0만 세면, 다른 출처에서 내려받은 파일까지 캐시 적중으로 묶을 수 있다. MDN의 transferSize 설명은 로컬 캐시와 교차 출처 정보 제한을 모두 0이 나오는 이유로 든다.
기존 크기 기반 판정에서는 transferSize가 0이면서 decodedBodySize가 양수인지를 함께 본다. 뒤의 값은 압축을 푼 본문 크기다. 둘 다 0이면 이 조건을 충족하지 않으므로, 캐시 적중으로 확정하지 않고 정보가 부족한 항목으로 남겨야 한다.
예를 들어 별도 CDN 도메인의 스크립트가 0바이트로 기록됐다고 해서 사용자의 네트워크를 전혀 쓰지 않았다고 결론 낼 수는 없다. 파일이 작다는 뜻과 파일 크기를 볼 수 없다는 뜻부터 구분해야 한다.
Firefox에서도 deliveryType을 함께 기록할 수 있다
Firefox 158은 PerformanceResourceTiming.deliveryType의 cache 값을 지원한다. 이 속성은 리소스의 전달 방식을 표시한다. 다만 지원 범위가 모든 브라우저에 같지는 않으므로 속성의 존재와 실제 값을 따로 기록하는 편이 좋다.
다음은 페이지에서 리소스별 값을 관찰하는 예시다. 처음부터 모든 항목을 ‘캐시’ 또는 ‘네트워크’ 두 종류로 나누지 않고, 판단에 필요한 원래 값을 남긴다.
const observer = new PerformanceObserver((list) => {
console.table(list.getEntries().map((entry) => ({
url: entry.name,
deliveryType: "deliveryType" in entry
? entry.deliveryType : "unsupported",
transferSize: entry.transferSize,
decodedBodySize: entry.decodedBodySize
})));
});
observer.observe({ type: "resource", buffered: true }); buffered: true는 이미 버퍼에 들어 있는 항목도 받게 한다. 이후 새 리소스 항목이 기록되면 콜백이 다시 실행된다. 이 예시의 unsupported는 설명을 위해 붙인 표시이며 브라우저 API가 정의한 전달 유형은 아니다.
deliveryType이 빈 문자열인 경우도 무조건 다운로드로 바꾸면 안 된다. 분류할 전달 유형이 없거나 노출이 제한된 경우를 남길 수 있어야 한다. 속성이 없는 브라우저와 속성이 있지만 빈 값을 준 브라우저도 구별한다.
정보를 열어 줄 헤더는 리소스 응답에 둔다
다른 출처의 파일 정보를 페이지에서 보게 하려면 리소스를 제공하는 서버의 Timing-Allow-Origin 응답 헤더를 확인한다. 예를 들어 다음은 https://app.example에 타이밍 정보 접근을 허용하는 설정이다.
Timing-Allow-Origin: https://app.example 앱 페이지의 응답에만 붙이거나 JavaScript에서 관찰 코드를 바꾸는 것으로 CDN 응답의 제한이 풀리지는 않는다. 자신이 관리하는 CDN이라면 실제 파일 응답에 헤더가 있는지 확인한다.
Resource Timing 규격은 이 헤더가 있어도 브라우저가 추가 교차 출처 제한을 적용할 수 있도록 한다. 헤더 하나를 모든 크기 값의 공개 보장으로 취급하지 말고, 실제 관찰값에 정보가 없는 경우를 유지해야 한다.
cache라고 해서 서버에 한 번도 묻지 않은 것은 아니다
HTTP 캐시는 저장해 둔 응답을 바로 쓰기도 하고, 서버에 아직 유효한지 확인한 뒤 쓰기도 한다. 캐시 재검증에서는 본문을 다시 받지 않아도 요청과 응답이 오간다. 캐시 사용률과 네트워크 요청이 없었던 비율은 같은 지표가 아니다.
규격의 cache 판정은 로컬 재사용과 재검증을 포함한다. 또한 이 값만으로 메모리 캐시와 디스크 캐시를 구분할 수 없다. 리소스가 빨리 도착했다는 이유만으로 저장 위치까지 단정해서는 안 된다.
서비스워커가 응답했다면 페이지의 타이밍에는 서비스워커와의 상호작용이 반영된다. 워커 내부에서 다시 수행한 네트워크 요청까지 보려면 워커 쪽 타임라인도 필요하다.
실제 집계에서는 확인된 캐시 사용과 정보 부족을 분리하고, 그 뒤에 재검증과 서비스워커 경로를 살피는 편이 맞다. 숫자 0을 성능 개선으로 읽기 전에, 그 숫자가 무엇을 공개하고 있는지 확인해야 한다.