リソースをプリフェッチすると、ページの読み込み時間が短縮され、ビジネス指標が改善されます。
プリフェッチは、近い将来に必要となる可能性が高いリソース(またはページ全体)をダウンロードすることで、ページの読み込みを高速化する手法です。調査によると、読み込み時間が短いほどコンバージョン率が上がり、ユーザー エクスペリエンスが向上します。
Terra はブラジル最大のコンテンツ ポータルの 1 つで、エンターテインメント、ニュース、スポーツを配信し、月間 6,300 万人以上のユニーク ビジターを抱えています。Google は Terra のエンジニアリング チームと協力して、ウェブサイトの特定のセクションでプリフェッチ技術を使用し、記事の読み込み時間を改善しました。
この事例紹介では、Terra の取り組みについて説明します。その結果、モバイルで広告のクリック率(CTR)が 11%、パソコンでの広告 CTR が 30%、Largest Contentful Paint(LCP)の回数が 50% 減少しました。
プリフェッチ戦略
プリフェッチは以前から存在していますが、すぐに必要でないリソースに余分な帯域幅を消費するため、慎重に使用する必要があります。この手法は、不要なデータ使用を避けるため、慎重に適用する必要があります。Terra の場合、記事は、次の条件を満たす場合にプリフェッチされます。
- プリフェッチされた記事へのリンクの可視性: Terra は、Intersection Observer API を使用して、プリフェッチしたい記事を含むセクションの視認性を検出しました。
- データ使用量の増加に適した条件: 前述のように、プリフェッチは、余分なデータを消費する推測的なパフォーマンス向上であり、すべての状況で望ましい結果になるとは限りません。帯域幅の浪費を減らすため、Terra は Network Information API と Device Memory API を使用して、次の記事を取得するかどうかを判断します。Terra は、次の場合にのみ次の記事を取得します。
- 接続速度が 3G 以上で、デバイスに 4 GB 以上のメモリが搭載されている。
- デバイスが iOS の場合はどうかを確認します。
- CPU アイドル状態: 最後に、Terra は
requestIdleCallback
を使用して、CPU がアイドル状態であり、追加の処理を実行できるかどうかを確認します。このコールバックは、メインスレッドがアイドル状態になったとき、または特定の(省略可)期限までに処理されます。
これらの条件に従うことで、Terra は必要な場合にのみデータを取得するため、帯域幅とバッテリーの消費を抑え、最終的に使用されなかったプリフェッチの影響を最小限に抑えることができます。
これらの条件が満たされると、Terra は、以下の青色でハイライト表示されている [関連コンテンツ] と [おすすめ] のセクションに表示される記事をプリフェッチします。
ビジネスへの影響
この手法の影響を測定するために、Terra はまず、記事ページの [関連コンテンツ] セクションでこの機能をリリースしました。UTM コードのおかげで、プリフェッチされた記事とプリフェッチされていない記事を区別して、比較できるようになりました。2 週間にわたる A/B テストが成功した後、Terra は「おすすめ」セクションにプリフェッチ機能を追加することにしました。
記事のプリフェッチの結果、広告指標が全体的に増加し、LCP とTime to First Byte(TTFB)時間が短縮されました。
プリフェッチは、慎重に使用すれば、ページの読み込み時間を大幅に短縮し、広告の指標を向上させ、LCP 時間を短縮できます。
詳細な技術情報
プリフェッチを行うには、rel=prefetch
や rel=preload
などのリソースヒントを使用するか、quicklink や Guess.js などのライブラリを使用するか、新しい Speculation Rules API を使用します。Terra では、優先度が低い fetch API と Intersection Observer インスタンスを組み合わせて、これを実装しています。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 をリストに追加します。 - プリフェッチ プロセスは
requestIdleCallback
でスケジュールされ、メインスレッドがアイドル状態のときにprefetch
関数を実行することを目的としています。
まとめ
プリフェッチを慎重に使用すると、今後のナビゲーション リクエストの読み込み時間を大幅に短縮できるため、ユーザー ジャーニーの摩擦を軽減し、エンゲージメントを高めることができます。プリフェッチを行うと、使用されない可能性のある余分なバイトが読み込まれるため、Terra では、ネットワークの状態が良好で、この情報が利用可能な対応デバイスでのみプリフェッチを行うように特別な手順を追加しました。
この取り組みに協力してくれた Terra のエンジニアリング チームの Gilberto Cocchi、Harry Theodoulou、Miguel Carlos Martínez Díaz、Barry Pollard、Jeremy Wagner、Leonardo Bellini と Lucca Paradeda に深く感謝します。