리소스를 미리 가져오면 페이지 로드 시간이 단축되고 비즈니스 측정항목이 향상됩니다.
미리 가져오기는 가까운 미래에 필요할 가능성이 있는 리소스 또는 전체 페이지를 다운로드하여 페이지 로드 속도를 높이는 데 사용되는 기법입니다. 연구에 따르면 로드 시간이 단축되면 전환율이 높아지고 사용자 환경이 개선됩니다.
Terra는 엔터테인먼트, 뉴스, 스포츠를 제공하는 브라질 최대의 콘텐츠 포털 중 하나로, 매월 순 방문자가 6,300만 명이 넘습니다. Google은 Terra 엔지니어링팀과 협력하여 웹사이트의 특정 섹션에서 미리 가져오기 기법을 사용하여 기사 로드 시간을 개선했습니다.
이 우수사례에서는 Terra의 여정 구현으로 모바일에서 광고 클릭률 (CTR)은 11%, 데스크톱에서 30%, 콘텐츠가 포함된 최대 페인트 (LCP) 횟수가 50% 감소했습니다.
미리 가져오기 전략
미리 가져오기는 오랫동안 사용되어 왔지만, 즉시 필요하지 않은 리소스에 추가 대역폭을 소비하므로 주의해서 사용하는 것이 중요합니다. 이 기법은 불필요한 데이터 사용을 방지하기 위해 신중하게 적용되어야 합니다. Terra의 경우 다음 조건이 충족되면 기사를 미리 가져옵니다.
- 미리 가져온 기사의 링크 공개 상태: Terra는 Intersection Observer API를 사용하여 미리 가져오려는 기사가 포함된 섹션의 조회가능성을 감지했습니다.
- 데이터 사용량 증가에 유리한 조건: 앞서 언급했듯이, 미리 가져오기는 추가 데이터를 소비하는 예측 성능 개선이며, 모든 상황에서 바람직한 결과는 아닐 수 있습니다. 대역폭 낭비 가능성을 줄이기 위해 Terra는 Network Information API와 Device Memory API를 사용하여 다음 도움말을 가져올지 결정합니다. Terra는 다음과 같은 경우에만 다음 도움말을 가져옵니다.
- 연결 속도가 3G 이상이고 기기에 메모리가 4GB 이상 있는 경우
- 또는 기기가 iOS를 실행 중인 경우
- CPU 유휴 상태: 마지막으로 Terra는 기본 스레드가 유휴 상태이거나 특정 기한 (선택사항)에 따라 처리되도록 콜백을 받는
requestIdleCallback
를 사용하여 CPU가 유휴 상태이고 추가 작업을 수행할 수 있는지 확인합니다.
이러한 조건을 준수하면 Terra는 필요한 경우에만 데이터를 가져와 대역폭과 배터리 수명을 절약하고 사용되지 않는 미리 가져오기의 영향을 최소화할 수 있습니다.
이러한 조건이 충족되면 Terra는 아래에 파란색으로 강조 표시된 "관련 콘텐츠" 및 "맞춤 추천" 섹션에 있는 기사를 미리 가져옵니다.
비즈니스 영향
Terra는 이 기법의 영향을 측정하기 위해 먼저 도움말 페이지의 '관련 콘텐츠' 섹션에서 이 기능을 출시했습니다. UTM 코드를 사용하여 프리패치된 기사와 프리패치되지 않은 기사를 비교할 수 있었습니다. 2주간 A/B 테스트를 성공적으로 진행한 후 테라는 '추천 항목' 섹션에 미리 가져오기 기능을 추가하기로 했습니다.
기사를 미리 가져온 결과, 광고 측정항목이 전반적으로 증가하고 LCP와 첫 바이트까지의 시간 (TTFB) 시간이 감소했습니다.
프리페칭은 주의해서 사용할 경우 페이지 로드 시간을 크게 개선하고, 광고 측정항목을 늘리며, LCP 시간을 단축합니다.
기술 세부정보
미리 가져오기는 rel=prefetch
또는 rel=preload
와 같은 리소스 힌트를 사용하거나 quicklink 또는 Guess.js와 같은 라이브러리를 통해 또는 최신 Speculation Rules API를 통해 실행할 수 있습니다. Terra는 우선순위가 낮은 fetch API를 Intersection Observer 인스턴스와 함께 사용하여 이를 구현하기로 결정했습니다. Terra는 rel=prefetch
또는 Speculation Rules API와 같은 다른 미리 가져오기 메서드를 아직 지원하지 않는 Safari를 지원할 수 있고 완전한 기능을 갖춘 JavaScript 라이브러리가 Terra의 요구에도 필요하지 않았기 때문에 이러한 선택을 했습니다.
아래 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
로 예약됩니다.
결론
주의해서 사용하면 미리 가져오기가 향후 탐색 요청의 로드 시간을 크게 줄여 사용자 여정의 마찰을 줄이고 참여도를 높일 수 있습니다. 미리 가져오기를 수행하면 사용되지 않을 수 있는 추가 바이트가 로드되므로 Terra는 네트워크 상태가 양호하고 이 정보를 사용할 수 있는 기기에서만 미리 가져오기 위해 추가 조치를 취했습니다.
이 작업에 기여해 주신 테라 엔지니어링팀의 질베르토 코키, 해리 테오둘루, 미구엘 카를로스 마르티네스 디아즈, 배리 폴라드, 제레미 바그너, 레오나르도 벨리니, 루카 파라데다님께 감사의 말씀을 전합니다.