리소스를 미리 가져오면 페이지 로드 시간이 단축되고 비즈니스 측정항목이 개선됩니다.
미리 가져오기는 가까운 시일 내에 필요할 가능성이 있는 리소스 또는 전체 페이지를 다운로드하여 페이지 로드 속도를 높이는 데 사용되는 기법입니다. 연구에 따르면 로드 시간이 빨라질수록 전환율이 높아지고 사용자 환경이 개선되는 것으로 나타났습니다.
Terra는 브라질에서 가장 큰 콘텐츠 포털 중 하나로, 엔터테인먼트, 뉴스, 스포츠를 제공하며 월간 순 방문자 수가 6,300만 명이 넘습니다. Google은 Terra의 엔지니어링팀과 협력하여 웹사이트의 특정 섹션에 미리 가져오기 기법을 사용하여 기사의 로드 시간을 개선했습니다.
이 케이스 스터디에서는 Terra의 여정 구현을 통해 모바일의 광고 클릭률 (CTR)이 11%, 데스크톱의 광고 CTR이 30% 증가하고 최대 콘텐츠 렌더링 시간 (LCP)이 50% 감소한 사례를 설명합니다.
미리 가져오기 전략
프리페칭은 오래 전부터 사용되어 왔지만, 즉시 필요하지 않은 리소스에 추가 대역폭을 소비하므로 주의해서 사용해야 합니다. 이 기법은 불필요한 데이터 사용을 방지하기 위해 신중하게 적용해야 합니다. Terra의 경우 다음 조건이 충족되면 기사가 미리 로드됩니다.
- 미리 로드된 기사 링크의 가시성: Terra는 Intersection Observer API를 사용하여 미리 로드하려는 기사가 포함된 섹션의 조회가능성을 감지했습니다.
- 데이터 사용량 증가에 유리한 조건: 앞에서 언급한 바와 같이 prefetching은 추가 데이터를 소비하는 추측 성능 개선이며 모든 상황에서 바람직한 결과가 아닐 수 있습니다. 대역폭 낭비 가능성을 줄이기 위해 Terra는 Device Memory API와 함께 Network Information API를 사용하여 다음 도움말을 가져올지 결정합니다. Terra는 다음과 같은 경우에만 다음 도움말을 가져옵니다.
- 연결 속도가 3G 이상이고 기기에 메모리가 4GB 이상 있습니다.
- 또는 기기가 iOS를 실행하는 경우
- CPU 유휴 상태: 마지막으로 Terra는 CPU가 유휴 상태이고 추가 작업을 실행할 수 있는지 확인합니다. 이를 위해
requestIdleCallback
를 사용합니다. 이 함수는 기본 스레드가 유휴 상태일 때 처리할 콜백을 가져오거나 특정(선택사항) 기한(둘 중 먼저 오는 값)을 사용합니다.
이러한 조건을 준수하면 Terra가 필요한 경우에만 데이터를 가져오므로 대역폭과 배터리 수명이 절약되고 사용되지 않는 미리 가져오기의 영향이 최소화됩니다.
이러한 조건이 충족되면 Terra는 아래 파란색으로 강조 표시된 '관련 콘텐츠' 및 '추천' 섹션에 있는 도움말을 미리 로드합니다.
비즈니스 영향
이 기법의 효과를 측정하기 위해 Terra는 먼저 도움말 페이지의 '관련 콘텐츠' 섹션에 이 기능을 출시했습니다. UTM 코드를 사용하면 비교 목적으로 미리 로드된 기사와 미리 로드되지 않은 기사를 구분할 수 있었습니다. 2주간의 A/B 테스트가 성공적으로 끝난 후 Terra는 '추천' 섹션에 미리 로드 기능을 추가하기로 결정했습니다.
기사를 미리 로드한 결과 광고 측정항목이 전반적으로 증가하고 LCP 및 TTFB (Time To First Byte) 시간이 감소했습니다.
주의해서 사용하면 페이지 로드 시간이 크게 개선되고 광고 측정항목이 증가하며 LCP 시간이 줄어듭니다.
기술 세부정보
미리 가져오기는 rel=prefetch
또는 rel=preload
와 같은 리소스 힌트를 사용하거나 quicklink 또는 Guess.js와 같은 라이브러리를 통해 또는 최신 Speculation Rules API를 사용하여 실행할 수 있습니다. Terra는 Intersection Observer 인스턴스와 함께 낮은 우선순위로 fetch API를 사용하여 이를 구현하기로 했습니다. Terra는 아직 rel=prefetch
또는 Speculation Rules API와 같은 다른 미리 로드 방법을 지원하지 않는 Safari를 지원할 수 있고 Terra의 요구사항에 모든 기능을 갖춘 JavaScript 라이브러리가 필요하지 않았기 때문에 이 방법을 선택했습니다.
아래 JavaScript는 Terra에서 사용하는 코드와 거의 같습니다.
function prefetch(nodeLists) {
// Exclude slow ECTs < 3g
if (navigator.connection &&
(navigator.connection.effectiveType === 'slow-2g'
|| navigator.connection.effectiveType === '2g')
) {
return;
}
// Exclude low end device which is device with memory <= 2GB
if (navigator.deviceMemory && navigator.deviceMemory <= 2) {
return;
}
const fetchLinkList = {};
const observer = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
if (!fetchLinkList[entry.target.href]) {
fetchLinkList[entry.target.href] = true;
fetch(entry.target, {
priority: 'low'
});
}
observer.unobserve(entry = entry.target);
}
});
});
}
const idleCallback = window.requestIdleCallback || function (cb) {
let start = Date.now();
return setTimeout(function () {
cb({
didTimeout: false,
timeRemaining: function () {
return Math.max(0, 50 - (Date.now() - start));
}
});
}, 1);
}
idleCallback(function () {
prefetch(nodeLists)
})
prefetch
함수는 먼저 최소 연결 품질과 기기 메모리를 확인한 후 미리 가져오기를 시작합니다.- 그런 다음
IntersectionObserver
를 사용하여 요소가 표시 영역에 표시되는 시점을 모니터링하고, 그 후 URL을 목록에 추가하여 미리 로드합니다. - prefetch 프로세스는
requestIdleCallback
로 예약되며, 기본 스레드가 유휴 상태일 때prefetch
함수를 실행하는 것을 목표로 합니다.
결론
주의해서 사용하면 미리 로드하면 향후 탐색 요청의 로드 시간이 크게 줄어들어 사용자 여정에서 발생하는 불편을 줄이고 참여도를 높일 수 있습니다. 미리 가져오면 사용되지 않을 수도 있는 추가 바이트가 로드되므로 Terra는 이 정보를 사용할 수 있는 양호한 네트워크 상태와 지원되는 기기에서만 미리 가져오도록 추가 단계를 취했습니다.
이 작업에 도움을 주신 Gilberto Cocchi, Harry Theodoulou, Miguel Carlos Martínez Díaz, Barry Pollard, Jeremy Wagner, Terra 엔지니어링팀의 Leonardo Bellini, Lucca Paradeda에게 감사의 인사를 전합니다.