命令型キャッシュ ガイド

Andrew Guan
Andrew Guan

ウェブサイトによっては、Service Worker と通信する際に、 結果を通知します次に例を示します。

  • ページから Service Worker に URL のリストが プリフェッチ機能を実装して、ユーザーが キャッシュ内で使用可能なドキュメントまたはページのサブリソースをリンクすると、後続の はるかに迅速に移動できるようになります
  • このページから、上位の記事を取得してキャッシュに保存し、 オフラインで使用できます

この種の重要でないタスクを Service Worker に委任すると、 ユーザー操作への応答など、差し迫ったタスクを適切に処理するためのメインスレッドを作成します。

キャッシュに保存するリソースを Service Worker にリクエストするページの図。

このガイドでは、ページから一方向のコミュニケーション手法を実装する方法について説明します。 標準のブラウザ API と Workbox ライブラリを使用して Service Worker を操作します。これらのタイプを 命令型キャッシュを使用します。

本番環境ケース

1-800-Flowers.com は、以下を使用して Service Worker による命令型キャッシュ(プリフェッチ)を実装しました。 postMessage() を使用して、 カテゴリページの上位の項目を表示することで、その後の商品の詳細ページへの移動を高速化します。

1 ~ 800 花のロゴ。

プリフェッチするアイテムの決定には、さまざまなアプローチが使用されます。

  • ページの読み込み時に、上位 9 つのアイテムの JSON データを取得するよう Servicer Worker にリクエストします。 結果のレスポンス オブジェクトをキャッシュに追加します。
  • 残りのアイテムについては、mouseover イベントがトリガーされ、 ユーザーがアイテムの上にカーソルを移動すると、「オンデマンドで」リソースの取得がトリガーされます。

Cache API を使用して JSON を保存します。 回答:

<ph type="x-smartling-placeholder">
</ph> 1 ~ 800 花のロゴ。
1-800Flowers.com の商品リスティング ページから JSON 商品データをプリフェッチします。

ユーザーがアイテムをクリックすると、そのアイテムに関連付けられた JSON データがキャッシュから取得されます。 ネットワークに接続する必要がないため、移動が速くなります。

ワークボックスの使用

Workbox では、メッセージを簡単に送信 Service Worker(workbox-window パッケージ経由)のモジュール セット ウィンドウのコンテキストで実行することを想定した API です。他のワークボックス パッケージを補完する 使用されます

ページを Service Worker と通信するには、まずページへの Workbox オブジェクト リファレンスを取得します。 登録済みの Service Worker:

const wb = new Workbox('/sw.js');
wb.register();

そうすれば、宣言的にメッセージを直接送信できます。 登録、有効化の確認、基盤となる通信 API の検討などに役立ちます。

wb.messageSW({"type": "PREFETCH", "payload": {"urls": ["/data1.json", "data2.json"]}}); });

Service Worker は、アプリケーションの message ハンドラを実装し、 確認しましょう。オプションとしてレスポンスを返すこともできますが、このような場合、 不要:

self.addEventListener('message', (event) => {
  if (event.data && event.data.type === 'PREFETCH') {
    // do something
  }
});

ブラウザの API を使用する

Workbox ライブラリではニーズを満たせない場合に、Window to Service を実装する方法を紹介します。 ブラウザ API を使用して通信できます。

postMessage API を使用して、ページから Service Worker への一方向の通信メカニズムを確立できます。

ページから呼び出します postMessage(): Service Worker インターフェース:

navigator.serviceWorker.controller.postMessage({
  type: 'MSG_ID',
  payload: 'some data to perform the task',
});

Service Worker は、アプリケーションの message ハンドラを実装し、 確認しましょう。

self.addEventListener('message', (event) => {
  if (event.data && event.data.type === MSG_ID) {
    // do something
  }
});

{type : 'MSG_ID'} 属性は必須ではありませんが、ページに対して さまざまな種類の命令を Service Worker に送信します(「プリフェッチ」と「クリア」 storage」です。Service Worker は、このフラグに基づいて異なる実行パスに分岐できます。

オペレーションが成功すれば、ユーザーはメリットを得られますが、そうでない場合、メインのユーザーフローは変更されません。たとえば、「1-800-Flowers.com」が事前キャッシュしようとした場合、Service Worker が成功したかどうかをページで知る必要はありません。搭載されていれば、ユーザーはより高速なナビゲーションを利用できます。そうでない場合は、引き続き新しいページに移動する必要があります。もう少し時間がかかる見込みです。

プリフェッチの簡単な例

命令型キャッシュの最も一般的な用途の 1 つは、プリフェッチです。 ユーザーが移動する前に、特定の URL にリソースを付与して、移動のスピードを上げる必要があります。

サイトにプリフェッチを実装する方法はいくつかあります。

ドキュメントのプリフェッチや特定のアセット(JS、 CSS など)を含む、これらの手法が最適なアプローチです。

たとえば、プリフェッチ リソース(JSON ファイルまたはページ)を 内部 URL を取得するには、このタスクを完全に 使用します。

このタイプのオペレーションを Service Worker に委任すると、次のようなメリットがあります。

  • 取得と取得後処理( セカンダリスレッドにルーティングしますこれにより、メインスレッドが解放され、より重要な ユーザーの操作への応答といったタスクを実行できます。
  • 複数のクライアント(タブなど)が共通の機能を再利用できるようにするとともに、 複数のサービスを同時に使用できます。

商品の詳細ページをプリフェッチする

最初に postMessage() を使用: キャッシュする URL の配列を渡します。

navigator.serviceWorker.controller.postMessage({
  type: 'PREFETCH',
  payload: {
    urls: [
      'www.exmaple.com/apis/data_1.json',
      'www.exmaple.com/apis/data_2.json',
    ],
  },
});

Service Worker で、以下を行う message ハンドラを実装します。 アクティブなタブから送信されたメッセージをインターセプトして処理します。

addEventListener('message', (event) => {
  let data = event.data;
  if (data && data.type === 'PREFETCH') {
    let urls = data.payload.urls;
    for (let i in urls) {
      fetchAsync(urls[i]);
    }
  }
});

前のコードでは、fetchAsync() という小さなヘルパー関数を導入し、 URL の配列を作成し、それぞれに対してフェッチ リクエストを発行します。

async function fetchAsync(url) {
  // await response of fetch call
  let prefetched = await fetch(url);
  // (optionally) cache resources in the service worker storage
}

レスポンスを取得する際に、リソースのキャッシュ ヘッダーを使用できます。多くの場合 ただし、商品の詳細ページと同様に、リソースはキャッシュに保存されません(つまり、 no-cacheCache-control ヘッダー)。このような場合は、次の方法でこの動作をオーバーライドできます。 取得したリソースを Service Worker のキャッシュに保存します。この方法には、インフラストラクチャの オフラインのシナリオで提供する必要があります

JSON データの枠を超えて

サーバー エンドポイントから取得された JSON データには、多くの場合、他の URL も この第 1 レベルに関連する画像やその他のエンドポイント データなど、プリフェッチに値 分析できます

この例では、返される JSON データが食料品店サイトの情報であるとします。

{
  "productName": "banana",
  "productPic": "https://cdn.example.com/product_images/banana.jpeg",
  "unitPrice": "1.99"
 }

fetchAsync() コードを変更して商品リストを反復処理し、ヒーロー画像をキャッシュに保存します。 それぞれ:

async function fetchAsync(url, postProcess) {
  // await response of fetch call
  let prefetched = await fetch(url);

  //(optionally) cache resource in the service worker cache

  // carry out the post fetch process if supplied
  if (postProcess) {
    await postProcess(prefetched);
  }
}

async function postProcess(prefetched) {
  let productJson = await prefetched.json();
  if (productJson && productJson.product_pic) {
    fetchAsync(productJson.product_pic);
  }
}

404 のような状況の場合、このコードの例外処理を追加できます。 しかし、Service Worker を使用してプリフェッチする利点は、 影響する場合もありますさらに複雑なロジックを記述して、 プリフェッチされたコンテンツの後処理により、コンテンツの柔軟性が高まり、コンテンツ内のデータと分離されます。 考えてみましょう扱う内容に制限はありません。

まとめ

この記事では、ページとサービス間の一方向通信の一般的なユースケースについて説明しました。 worker: 命令型キャッシュ。ここで紹介した例は、Google Cloud で このパターンを使用し、同じアプローチを他のユースケースにも適用できます。たとえば、 人気記事をオンデマンドでキャッシュし、オフラインでの利用、ブックマークなどに利用できます。

ページと Service Worker のその他の通信パターンについては、以下をご覧ください。

  • 更新のブロードキャスト: Service Worker からページを呼び出して、 重要な更新について通知を受け取れます(たとえば、ウェブアプリの新しいバージョンが利用可能になったときなど)。
  • 双方向通信: タスクを Service Worker に委任する(例: 読み込みの負荷が大きくなるなど)、進行状況はページに継続的に報告されます。