2015 年に、バックグラウンド同期を導入しました。これにより、サービス ワーカーはユーザーが接続するまで処理を延期できます。つまり、ユーザーはメッセージを入力して送信ボタンを押した後、メッセージがすぐに送信されるか、接続が確立されたときに送信されることを理解したうえでサイトを離れることができます。
これは便利な機能ですが、取得中は Service Worker が存続している必要があります。これは、メッセージの送信などの短い処理では問題ありませんが、タスクに時間がかかりすぎると、ブラウザはサービス ワーカーを強制終了します。そうしないと、ユーザーのプライバシーとバッテリーにリスクが生じます。
映画、ポッドキャスト、ゲームのレベルなど、ダウンロードに時間がかかるコンテンツをダウンロードする必要がある場合はどうすればよいですか?そのために、バックグラウンド フェッチを使用します。
バックグラウンド フェッチは、Chrome 74 以降ではデフォルトで使用できます。
バックグラウンド フェッチを使用する場合と使用しない場合の状態を示す 2 分間のデモを以下に示します。
仕組み
バックグラウンド フェッチは次のように機能します。
- ブラウザに、一連の取得をバックグラウンドで実行するよう指示します。
- ブラウザはこれらのものを取得し、進捗状況をユーザーに表示します。
- 取得が完了または失敗すると、ブラウザはサービス ワーカーを開き、イベントを発生させて結果を通知します。ここで、レスポンスをどのように処理するかを決定します。
ユーザーがステップ 1 の後にサイトのページを閉じても、ダウンロードは続行されます。取得は非常に目立つため、簡単に中止できます。そのため、バックグラウンド同期タスクが長すぎるというプライバシーに関する懸念はありません。Service Worker は常に実行されているわけではないため、バックグラウンドでビットコインをマイニングするなど、システムを不正使用する心配はありません。
一部のプラットフォーム(Android など)では、ブラウザがオペレーティング システムに取得を任せることができるため、ステップ 1 の後にブラウザを閉じることができます。
ユーザーがオフライン中にダウンロードを開始した場合や、ダウンロード中にオフラインになった場合、バックグラウンド取得は一時停止され、後で再開されます。
API
機能検出
他の新機能と同様に、ブラウザがこの機能をサポートしているかどうかを検出する必要があります。バックグラウンド フェッチは、次のように簡単にできます。
if ('BackgroundFetchManager' in self) {
// This browser supports Background Fetch!
}
バックグラウンド フェッチの開始
メインの API は Service Worker の登録を待機するため、まず Service Worker を登録してください。以下の手順を行います。
navigator.serviceWorker.ready.then(async (swReg) => {
const bgFetch = await swReg.backgroundFetch.fetch('my-fetch', ['/ep-5.mp3', 'ep-5-artwork.jpg'], {
title: 'Episode 5: Interesting things.',
icons: [{
sizes: '300x300',
src: '/ep-5-icon.png',
type: 'image/png',
}],
downloadTotal: 60 * 1024 * 1024,
});
});
backgroundFetch.fetch
は次の 3 つの引数を取ります。
パラメータ | |
---|---|
id |
string : このバックグラウンド フェッチを一意に識別します。 ID が既存のバックグラウンド取得と一致する場合、 |
requests |
Array<Request|string>
取得対象。文字列は URL として扱われ、 new Request(theString) によって Request に変換されます。リソースで CORS による許可されている限り、他の生成元から取得できます。 注: Chrome は現在、CORS プリフライトを必要とするリクエストをサポートしていません。 |
options |
以下を含むことができるオブジェクト。 |
options.title |
string 進行状況とともにブラウザに表示するタイトル。 |
options.icons |
Array<IconDefinition> 「src」、「size」、「type」を含むオブジェクトの配列。 |
options.downloadTotal |
number レスポンス本文の合計サイズ(GZIP 解凍後)。 これは省略可能ですが、入力することを強くおすすめします。ダウンロードのサイズをユーザーに伝え、進行状況情報を提供するのに使用されます。指定しない場合、ブラウザはユーザーにサイズが不明であることを通知し、その結果、ユーザーがダウンロードを中止する可能性が高くなります。 バックグラウンド フェッチのダウンロード数がここに指定された数を超えると、中断されます。ダウンロード サイズが |
backgroundFetch.fetch
は、BackgroundFetchRegistration
で解決される Promise を返します。詳細については後で説明します。ユーザーがダウンロードをオプトアウトしているか、指定されたパラメータのいずれかが無効な場合、Promise は拒否されます。
1 つのバックグラウンド フェッチに対して複数のリクエストを指定すると、ユーザーにとって論理的に 1 つのリクエストとして扱われるものを組み合わせることができます。たとえば、映画は 1,000 個のリソースに分割され(MPEG-DASH で一般的)、画像などの追加リソースが付属している場合があります。ゲームのレベルは、多くの JavaScript、画像、音声リソースに分散できます。ただし、ユーザーにとっては「映画」や「レベル」にすぎません。
既存のバックグラウンド フェッチの取得
既存のバックグラウンド フェッチは次のように取得できます。
navigator.serviceWorker.ready.then(async (swReg) => {
const bgFetch = await swReg.backgroundFetch.get('my-fetch');
});
必要なバックグラウンド フェッチの id を渡します。その ID でアクティブなバックグラウンド フェッチがない場合、get
は undefined
を返します。
バックグラウンド取得は、登録された瞬間から、成功、失敗、または中止されるまで「アクティブ」と見なされます。
getIds
を使用すると、アクティブなバックグラウンド取得のリストを取得できます。
navigator.serviceWorker.ready.then(async (swReg) => {
const ids = await swReg.backgroundFetch.getIds();
});
バックグラウンド フェッチの登録
BackgroundFetchRegistration
(上記の例では bgFetch
)には次のものがあります。
プロパティ | |
---|---|
id |
string バックグラウンド フェッチの ID。 |
uploadTotal |
number サーバーに送信されるバイト数。 |
uploaded |
number 正常に送信されたバイト数。 |
downloadTotal |
number バックグラウンド フェッチの登録時に指定された値、またはゼロ。 |
downloaded |
number 正常に受信されたバイト数。 この値は減少する可能性があります。たとえば、接続が切断され、ダウンロードを再開できない場合、ブラウザはそのリソースの取得を最初からやり直します。 |
result |
次のいずれかになります。
|
failureReason |
次のいずれかになります。
|
recordsAvailable |
boolean 基盤となるリクエスト/レスポンスにアクセスできますか? これが false になると、 |
メソッド | |
abort() |
Promise<boolean> を返します。バックグラウンド取得を中止します。 取得が正常に中止された場合、返された Promise は true で解決します。 |
matchAll(request, opts) |
Promise<Array<BackgroundFetchRecord>> を返します。リクエストとレスポンスを取得します。 ここでの引数は、キャッシュ API と同じです。引数なしで呼び出すと、すべてのレコードに対する Promise が返されます。 詳しくは以下をご覧ください。 |
match(request, opts) |
Promise<BackgroundFetchRecord> を返します。上記と同じですが、最初の一致で解決します。 |
イベント | |
progress |
uploaded 、downloaded 、result 、failureReason のいずれかが変更されたときにトリガーされます。 |
進捗状況の追跡
これは progress
イベントを介して行えます。downloadTotal
は指定した値になります。値を指定しない場合は 0
になります。
bgFetch.addEventListener('progress', () => {
// If we didn't provide a total, we can't provide a %.
if (!bgFetch.downloadTotal) return;
const percent = Math.round(bgFetch.downloaded / bgFetch.downloadTotal * 100);
console.log(`Download progress: ${percent}%`);
});
リクエストとレスポンスの取得
bgFetch.match('/ep-5.mp3').then(async (record) => {
if (!record) {
console.log('No record found');
return;
}
console.log(`Here's the request`, record.request);
const response = await record.responseReady;
console.log(`And here's the response`, response);
});
record
は BackgroundFetchRecord
で、次のように表示されます。
プロパティ | |
---|---|
request |
Request 指定されたリクエスト。 |
responseReady |
Promise<Response> 取得されたレスポンス。 レスポンスはプロミスの後ろにあるため、まだ受信されていない可能性があります。取得に失敗した場合、Promise は拒否されます。 |
Service Worker イベント
イベント | |
---|---|
backgroundfetchsuccess |
すべて正常に取得されました。 |
backgroundfetchfailure |
1 つ以上の取得が失敗しました。 |
backgroundfetchabort |
1 つ以上の取得が失敗しました。
これは、関連データをクリーンアップする場合にのみ有用です。 |
backgroundfetchclick |
ユーザーがダウンロード プログレス UI をクリックしました。 |
イベント オブジェクトには次のものがあります。
プロパティ | |
---|---|
registration |
BackgroundFetchRegistration |
メソッド | |
updateUI({ title, icons }) |
最初に設定したタイトルやアイコンを変更できます。これは省略可能ですが、必要に応じて追加のコンテキストを提供できます。これは、backgroundfetchsuccess イベントと backgroundfetchfailure イベント中に *1 回* だけ実行できます。 |
成功/失敗への対応
progress
イベントはすでに説明しましたが、これはユーザーがサイトのページを開いている間のみ有用です。バックグラウンド取得の主なメリットは、ユーザーがページを離れた、またはブラウザを閉じた後も、処理が継続されることです。
バックグラウンド取得が正常に完了すると、Service Worker は backgroundfetchsuccess
イベントを受信し、event.registration
がバックグラウンド取得の登録になります。
このイベントの発生後、フェッチされたリクエストとレスポンスにはアクセスできなくなります。保持する場合は、cache API などの場所に移動します。
ほとんどの Service Worker イベントと同様に、event.waitUntil
を使用して、Service Worker がイベントの完了を認識できるようにします。
たとえば、サービス ワーカーで次のように指定します。
addEventListener('backgroundfetchsuccess', (event) => {
const bgFetch = event.registration;
event.waitUntil(async function() {
// Create/open a cache.
const cache = await caches.open('downloads');
// Get all the records.
const records = await bgFetch.matchAll();
// Copy each request/response across.
const promises = records.map(async (record) => {
const response = await record.responseReady;
await cache.put(record.request, response);
});
// Wait for the copying to complete.
await Promise.all(promises);
// Update the progress notification.
event.updateUI({ title: 'Episode 5 ready to listen!' });
}());
});
失敗は 404 が 1 つだけだった可能性があり、これは重要ではない可能性があります。そのため、上記のように一部のレスポンスをキャッシュにコピーする価値がある場合があります。
クリックへの対応
ダウンロードの進行状況と結果を示す UI はクリック可能です。Service Worker の backgroundfetchclick
イベントを使用すると、これに応答できます。上記のように、event.registration
はバックグラウンド取得登録になります。
このイベントで一般的に行われる処理は、ウィンドウを開くことです。
addEventListener('backgroundfetchclick', (event) => {
const bgFetch = event.registration;
if (bgFetch.result === 'success') {
clients.openWindow('/latest-podcasts');
} else {
clients.openWindow('/download-progress');
}
});
参考情報
修正: この記事の以前のバージョンでは、バックグラウンド フェッチを「ウェブ標準」と誤って表記していました。この API は現在標準化の過程には含まれません。仕様は、WICG のコミュニティ グループ レポートのドラフトとして確認できます。