ウェブページがデータを(または「ビーコン」を)サーバーに送り返す必要があることはよくあります。たとえば、ユーザーの現在のセッションのアナリティクス データなどです。デベロッパーにとって、これにはバランスのとれた対応が必要です。つまり、ビーコンの送信前にタブを閉じたりユーザーが移動したりした場合に、データが失われるリスクを負うことなく、一定回数(場合によっては冗長なリクエスト)を減らす必要があります。
従来、デベロッパーは pagehide
イベントと visibilitychange
イベントを使用してページのアンロード時にページをキャッチしてから、navigator.sendBeacon()
または fetch()
と keepalive
を使用してデータをビーコンしていました。ただし、どちらのイベントにも、ユーザーのブラウザによって異なる難しいコーナーケースがあり、特にモバイルではイベントがまったく届かないこともあります。
fetchLater()
は、この複雑さを単一の API 呼び出しに置き換えるプロポーザルです。その名のとおり、ページが閉じられたり、ユーザーが他の場所に移動したりした場合でも、将来的にいずれかの時点でリクエストが行われるようブラウザに指示します。
fetchLater()
は、Chrome のオリジン トライアルで、実際のユーザーを対象にテストできます。このトライアルは、バージョン 121(2024 年 1 月にリリース)から 2024 年 9 月 3 日まで実施されます。
fetchLater()
API
const fetchLaterResult = fetchLater(request, options);
fetchLater()
は 2 つの引数を取ります。通常、これらの引数は fetch()
の引数と同じです。
request
。文字列 URL またはRequest
インスタンス。- オプションの
options
オブジェクト。fetch()
のoptions
をactivateAfter
というタイムアウトで拡張します。
fetchLater()
は FetchLaterResult
を返します。これには現在、読み取り専用のプロパティ activated
が 1 つだけ含まれています。このプロパティは、「後で」経過し、フェッチが行われたときに true
に設定されます。fetchLater()
リクエストに対するレスポンスは破棄されます。
request
最も簡単な使用方法は、URL をそのまま使用することです。
fetchLater('/endpoint/');
ただし、fetch()
と同様に、fetchLater()
リクエストには、カスタム ヘッダー、認証情報の動作、POST
本文、キャンセルする可能性がある AbortController
signal
など、多数のオプションを設定できます。
fetchLater('/endpoint/', {
method: 'GET',
cache: 'no-store',
mode: 'same-origin',
headers: {Authorization: 'SUPER_SECRET'},
});
options
options オブジェクトは、タイムアウト後にリクエストを実行する場合や、ページが読み込まれなくなった場合に、fetch()
のオプションをタイムアウト activateAfter
で拡張します。
これにより、絶対に最後の瞬間にデータを取得するか、よりタイムリーなタイミングでデータを取得するかのトレードオフを決定できます。
たとえば、ユーザーが通常は 1 日中開いたままにするアプリの場合は、1 時間のタイムアウトを設定して、より詳細な分析を可能にしながら、ユーザーが 1 時間以内にアプリを終了した場合でもビーコンを送信できるようにします。その後、1 時間の分析用に新しい fetchLater()
を設定できます。
const hourInMilliseconds = 60 * 60 * 1000;
fetchLater('/endpoint/', {activateAfter: hourInMilliseconds});
使用例:
フィールドで Core Web Vitals を測定する際の問題の一つは、ユーザーが実際にページを離れるまで、パフォーマンス指標が変化する可能性があることです。たとえば、大きなレイアウト シフトがいつでも発生する可能性があります。また、ページが操作に応答するまでにさらに時間がかかることもあります。
ただし、ページの読み込み時にビーコンにバグや不完全な点があるために、パフォーマンス データがすべて失われるリスクを冒すことは避けるべきです。fetchLater()
に最適です。
この例では、web-vitals.js ライブラリを使用して指標をモニタリングし、fetchLater()
を使用して結果をアナリティクス エンドポイントに報告します。
import {onCLS, onINP, onLCP} from 'web-vitals';
const queue = new Set();
let fetchLaterController;
let fetchLaterResult;
function updateQueue(metricUpdate) {
// If there was an already complete request for whatever
// reason, clear out the queue of already-sent updates.
if (fetchLaterResult?.activated) {
queue.clear();
}
queue.add(metricUpdate);
// JSON.stringify used here for simplicity and will likely include
// more data than you need. Replace with a preferred serialization.
const body = JSON.stringify([...queue]);
// Abort any existing `fetchLater()` and schedule a new one with
// the update included.
fetchLaterController?.abort();
fetchLaterController = new AbortController();
fetchLaterResult = fetchLater('/analytics', {
method: 'POST',
body,
signal: fetchLaterController.signal,
activateAfter: 60 * 60 * 1000, // Timeout to ensure timeliness.
});
}
onCLS(updateQueue);
onINP(updateQueue);
onLCP(updateQueue);
指標の更新が届くたびに、既存のスケジュール設定された fetchLater()
は AbortController
でキャンセルされ、更新が含まれた新しい fetchLater()
が作成されます。
fetchLater()
を試す
前述のとおり、fetchLater()
は Chrome 126 までオリジン トライアルでご利用いただけます。オリジン トライアルの背景情報については、オリジン トライアルの開始をご覧ください。
ローカルテストの場合は、chrome://flags/#enable-experimental-web-platform-features
の試験運用版ウェブ プラットフォームの機能フラグを使用して fetchLater
を有効にできます。これは、--enable-experimental-web-platform-features
、またはよりターゲットを絞った --enable-features=FetchLaterAPI
フラグを指定してコマンドラインから Chrome を実行することでも有効にできます。
公開ページで使用する場合は、使用する前にグローバル fetchLater
が定義されているかどうかを確認して、必ず機能検出を行います。
if (globalThis.fetchLater) {
// Set up beaconing using fetchLater().
// ...
}
フィードバック
新しいウェブ API を正しく機能させるには、デベロッパーからのフィードバックが不可欠です。GitHub で問題やフィードバックを提出してください。