この記事は Service worker を使い始めるための情報を提供するページです。基本的な構造、Service worker の登録、新しい Service worker のインストールと有効化のプロセス、Service worker の更新、キャッシュや応答の操作を含めた、オフラインで動作するシンプルなアプリケーションの機能についてです。

Service workerの前提条件

ウェブユーザーが長年苦しめられてきた主要な問題の一つは、接続を失うことです。世界中の最高のウェブアプリは、ダウンロードできないときの使い勝手が最悪でした。この問題を解決するために様々な技術の開発が試みられ、私たちのオフラインページが示すように、いくつかの問題は解決済みです。しかし、資産のキャッシュとネットワーク要求を全てコントロールする良いメカニズムはまだ存在しません。

以前の取組み - AppCache - は、キャッシュする資産をとても簡単に指定することが可能になるため、良いアイデアに見えました。しかしながら、 AppCache には利用において数多くの取り決めがあり、アプリケーションが完全に取り決めに従わない場合は壊れてしまいました。さらに詳しいことは Jake Archibald の Application Cache is a Douchebag にをお読みください。

メモ: Firefox 44 で AppCache がページのオフラインサポートを提供するために使用しようとすると、コンソールに警告メッセージが表示され、代わりに Service worker を使うように開発者にアドバイスするようになりました (バグ 1204581)。

Service worker は最終的にこれらの問題を解決するでしょう。Service workerの構文は AppCache の構文と比べて複雑です。しかし、代わりに JavaScript を使用して AppCache で動作させていたような振る舞いをより細かく制御し、この問題やその他の多くのことを扱うことができるようになります。Service workerを使用することで、アプリケーションがはじめにキャッシュされた資産を使用するよう簡単に設定することができます。そのため、一度ネットワークからデータを取得しておけば、オフラインでも既定の機能を提供できます (オフラインファーストとして一般的に知られています)。このようなオフラインの機能はネイティブアプリでは既に使用可能であり、ネイティブアプリがウェブアプリを差し置いて選ばれる理由の一つです。

Service worker を始めるための設定

多くの Service worker の機能は、それらに対応しているブラウザーの最新版ではじめから利用できるようになっています。もしデモコードがあなたの環境で動作しない場合は、以下のいずれかの設定を行い、有効化してください。

  • Firefox Nightly: about:config の画面で dom.serviceWorkers.enabled を true に設定し、ブラウザーを再起動してください。
  • Chrome Canary: chrome://flags の画面で experimental-web-platform-features を有効にし、ブラウザーを再起動してください(現在いくつかの機能はChromeでははじめから有効になっています)。
  • Opera: opera://flags の画面で Support for ServiceWorker を有効にし、ブラウザーを再起動してください。
  • Microsoft Edge: about:flags の画面で Enable service workers にチェックを入れ、ブラウザーを再起動してください。

また、コードは HTTPS を通して提供する必要があります。 — Service worker はセキュリティ上の理由から HTTPS を通して実行されるよう制限されています。そのため、 GitHub は HTTPS に対応しているので、実験を行うのによい場所です。ローカルでの開発を行うために、 localhost もブラウザーから安全なオリジンとみなされます。

基本構造

Service worker では、基本的なセットアップの際に下記のステップが一般的に見られます。

  1. Service worker の URL が呼び出され、 serviceWorker.register() を通して登録されます。
  2. 成功した場合、Service worker は ServiceWorkerGlobalScope で実行されます。これは根本的に特殊な worker コンテクストで、メインスレッドから独立しており、 DOM へのアクセスもありません。
  3. Service worker はイベントの処理ができる状態になりました。
  4. Service worker にコントロールされたページが今後アクセスされた時、worker のインストールが試みられます。インストールのイベントは常に最初に Service worker へ送られます(このイベントは IndexedDB の設定やサイト資産のキャッシュに使用することができます)。これはネイティブアプリや Firefox OS アプリのインストールと全く同じ種類 - 全てをオフラインで使用できるようにするための - の処理です。
  5. oninstall ハンドラーが完了すると、Service worker はインストールされたと考えられます。
  6. 次のステップは有効化です。Service worker がインストールされると、次に有効化イベントを受け取ります。 onactivate の基本的な使用法は、以前のバージョンの Service worker スクリプトで使用したリソースのクリーンアップです。
  7. 現在サービスワーカーはページを制御しているでしょう。しかし register() が成功した後に開かれたページのみです。例えば、文書は Service worker があろうとなかろうと実行され、実行されている間はその状態を保ちます。つまり、文書が実際に制御されるには、リロードされる必要があるでしょう。

以下の図は、利用可能な Service worker のイベントの概要を示しています。

インストール、起動、メッセージ、フェッチ、同期、プッシュ

Promise

Promise は複数の非同期の動作を実行する優れたメカニズムです。Service worker の働き方の中心となっています。
 

Promise は多く機能を持ちますが、ここでは何かが Promise を返したとき、末尾に .then() を繋げることによって、成功時や失敗時に呼ばれるコールバック関数を指定できること、そして失敗時に呼ばれるコールバック関数は最後に .catch() を挿入することで指定できること、この 2 つを知っておけば十分です。

昔ながらの同期的なコールバック構造と、それに相当する非同期的な promise を比較してみましょう。

sync

try {
  var value = myFunction();
  console.log(value);
} catch(err) {
  console.log(err);
}

async

myFunction().then(function(value) {
  console.log(value);
}).catch(function(err) {
  console.log(err);
});

初めの例では、私たちはほかのコードが実行できるようになる前に、 myFunction() が実行され、 value が返るのを待たなくてはなりません。2つ目の例では、 myFunction()valuepromise を返し、残りのコードも実行に移すことができます。 promise が解決されるとき、 then の中のコードが非同期的に実行されます。

それでは実例を - 動的に画像を読み込みたい、しかし表示しようとする以前の段階で読み込みが終了していることを確実にしたいときはどうするのでしょう。これは私たちがしたい標準的なことですが、少しの痛みとなることもあります。読み込まれた後に表示するためだけなら私たちは .onload を使用することができます。しかし私たちがリッスンするより前に起こり始めたイベントはどうなるのでしょう。私たちは .complete を使うこともできたでしょう。しかしそれはまだfoolproofではありません。複数の画像のときはどうするのでしょう。そしてそれは同期的に行われるため、メインスレッドをブロックしてしまいます。

代わりに、私たちはこのようなケースを操作するための独自の promise を作成することができます (Promise テストの例のソースコードを見てください)。

註: 実際の Service worker の導入では非推奨の XMLHttpRequest API よりもキャッシュと onfetch が使われるでしょう。 Promise の理解に集中できるようにそれらの機能はここでは使用されていません。

function imgLoad(url) {
  return new Promise(function(resolve, reject) {      
    var request = new XMLHttpRequest();
    request.open('GET', url);
    request.responseType = 'blob';

    request.onload = function() {
      if (request.status == 200) {
        resolve(request.response);
      } else {
        reject(Error('Image didn\'t load successfully; error code:' + request.statusText));
      }
    };

    request.onerror = function() {
      reject(Error('There was a network error.'));
    };

    request.send();
  });
}

私たちは resolvereject を引数に持つコールバック関数を引数にとる Promise() コンストラクタを使用して新しい promise を返します。この関数のどこかで、何が起きた時に成功とするか、また何が起きた時に失敗とするか - このケースでは 200 OK のステータスが返るかどうか - を定義し、成功時には resolve を、失敗時には reject を呼ぶ必要があります。関数内の残りの要素は、標準的な XHR のものですので、今は気にする必要はありません。

imgLoad() を呼ぶときは、私たちが期待している通り、読み込みたい画像への URL を一緒に呼ばなくてはなりません。しかし残りのコードは、少し異なります。

var body = document.querySelector('body');
var myImage = new Image();

imgLoad('myLittleVader.jpg').then(function(response) {
  var imageURL = window.URL.createObjectURL(response);
  myImage.src = imageURL;
  body.appendChild(myImage);
}, function(Error) {
  console.log(Error);
});

関数呼び出しの末尾に、二つの関数を持つ then() メソッドをつなげています。一つ目の関数は promise が成功として resolve されたときに実行されます。二つ目の関数は promise が失敗したときに呼び出されます。成功のケースでは、 myImage の中で画像を表示して、 body に付け加えています (この引数は promise の中の resolve メソッドに含まれる request.response です)。失敗のケースではコンソールにエラーを返しています。

これらはすべて非同期的に起こります。

メモ: 次のように promise の呼び出しを互いにつなげていくこともできます。
myPromise().then(success, failure).then(success).catch(failure);

メモ: Jake Archibald の素晴らしい JavaScript Promises: there and back again を読むことで promise についてのより多くの発見をすることができます。

Service worker のデモ

サービスワーカーの登録とインストールについてのとても基本的なデモンストレーションをするために、私たちは sw-test という、スターウォーズのレゴの画像を表示するシンプルなデモを作成しました。このデモでは、 JSON オブジェクトから画像データを取得し、 Ajax を使用してページの下の行にある画像が表示される前に画像を読み込むために、 Promise を活用した関数を使用しています。私たちは今のところ物事を固定的でシンプルに保っています。デモはまたサービスワーカーを登録し、インストールし、有効化します。そしてブラウザーがサポートしているときは必要なすべてのファイルをキャッシュし、オフラインで動作するでしょう。




GitHub でソースコードを見ることができます。またサンプルの動きも見ることができます。私たちがここで強調したいことの一つは Promise です (app.js の17-42行目を見てください)。上のほうで見た Promise のテストデモのコードを修正したものです。下記の部分が異なっています。

  1. オリジナルでは、ほしい画像を読み込むための URL を渡しているだけですが、今回のバージョンでは、一つの画像の全ての情報を含む JSON を渡しています(JSON がどのような形かは image-list.js を見てください)。これはそれぞれの Promise が resolve するすべてのデータが、非同期で動作するためには、 Promise とともに渡されなければならないためです。もし URL のみを渡し、 for() ループの中で後から JSON に含まれるほかの要素にアクセスしようとすると、 Promise が for() ループの進行と同時に resolve を返さないため、うまく動作しないでしょう (これは同期的な処理になります)。
  2. 配列とともに Promise は resolve されます。 resolve 後の関数で読み込まれた画像の Blob、画像名、クレジットや alt テキストを利用可能にするためです (app.js の26-29行目を見てください)。 Promise は一つの引数のみで resolve するので、もし複数の値とともに resolve したい場合は、配列かオブジェクトを使用する必要があります。
  3. resolve された Promise の値にアクセスするためには、 then が期待する関数を使用します (app.js の55-59行目を見てください)。初めは少し奇妙に見えるでしょうが、これが Promise の動き方です。

Service worker に入る

サービスワーカーを取得してみましょう!

worker を登録する

私たちのアプリの JavaScript ファイル— app.js —の最初のブロックは次の通りです。これは service worker を使用するエントリーポイントです。

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw-test/sw.js', {scope: '/sw-test/'})
  .then(function(reg) {
    // registration worked
    console.log('Registration succeeded. Scope is ' + reg.scope);
  }).catch(function(error) {
    // registration failed
    console.log('Registration failed with ' + error);
  });
}
  1. 外側のブロックは、登録を試みる前にサービスワーカーがサポートされているか確認する機能検出試験を行います。
  2. 次に、アプリ内にある単なる JavaScript ファイルであるサービスワーカーを、 ServiceWorkerContainer.register() 関数を使って、このサイトに登録します (なお、これはオリジンからのファイルの URL であって、 JS ファイルの参照ではありません)。
  3. scope 引数はオプションで、サービスワーカーが制御するコンテンツのサブセットを指定するために使用できます。このケースでは、'/sw-test/' を指定しており、アプリのオリジン配下のすべてのコンテンツを意味しています。もしこれを指定しなくてもこの値が既定値になりますが、指定方法を示すために使用しています。
  4. promise の構造に成功時の処理をチェーンするために、 .then() promise 関数を使用しています。 promise が成功裡に解決されたとき、内部のコードが実行されます。
  5. 最後に promise が拒否されたときに実行される .catch() 関数をチェーンします。

これは、 worker コンテクストで実行される Service worker を登録しているため、 DOM アクセスは含まれていません。続いて、通常ページの外側の Service worker でロードを制御するためにコードを実行します。

1つの Service worker で、複数のページを制御できます。スコープ内のページがロードされるたび、Service worker はそのページにインストールされて動作します。そのため、Service worker スクリプト内でのグローバル変数の扱いには注意が必要だということを心にとどめておいてください。各ページは独自の worker を持ちません。

メモ: サービスワーカー関数は、プロキシサーバーのように要求と応答を書き換えたり、キャッシュからの項目で置き換えたり、さまざまなことができます。

メモ: Service worker の良いところは、以上で見てきたような機能の検出をすることで、Service worker に対応していないブラウザーでもオンラインで期待通りの流儀でアプリを使用することができることです。さらに、同一のページで AppCache と Service worker を使用すると、Service workerに対応していないが AppCache に対応しているブラウザーは AppCache を使用し、両方に対応しているブラウザーは AppCache を無視して Service worker を優先させることができます。

Service worker の登録に失敗する理由

次の可能性が考えられます。

  1. HTTPS を使用してアプリケーションを実行していない。
  2. Service worker ファイルへのパスが正しく書かれていない。 — アプリのルートディレクトリではなく、アプリのオリジンからの相対パスで書く必要があります。上記の例では、worker が https://mdn.github.io/sw-test/sw.js にあり、アプリのルートは https://mdn.github.io/sw-test/ です。しかし、パスは /sw-test/sw.js と書く必要があり、 /sw.js ではありません。
  3. 指定されている Service worker がアプリとは異なるオリジンにある。これは許可されていません。

他のメモです。

  • Service worker は Service worker のスコープ内にあるクライアントからの要求のみを取得します。
  • Service worker の最大スコープは、worker のある場所です。
  • Service worker が Service-Worker-Allowed ヘッダーから提供されたクライアント上で起動する場合、その worker の最大スコープのリストを指定することができます。
  • Firefox では、ユーザーがプライベートブラウジングモードにいるときは、Service worker API は隠され使用することができません。

インストールと起動: キャッシュの作成

Service worker を登録した後、ブラウザーはページ/サイト上で Service worker をインストールおよび起動しようとします。

インストールが成功裡に完了したとき、 install イベントが発火されます。通常、 install イベントはオフラインで実行する必要のある資産を、ブラウザーのオフラインキャッシュ領域に配置するために使われます。これをするために、サービスワーカーの真新しい storage API— cache — を使用します。 cache はサービスワーカー上でグローバルに、応答で提供された資産を保存したり、要求にキーしたりできます。この API はブラウザーの標準キャッシュと同じようにふるまいますが、ドメインに特化しています。キャッシュが不要であることを再度伝えるまで存在します。つまり、すべてを制御できます。

メモ: Cache API はすべてのブラウザーが対応しているわけではありません (詳細はBrowser supportのセクションを見てください)。今すぐこれを使いたいなら、 Google's Topeka demo で利用されているポリフィルの使用か、 IndexedDB に資産を格納することを検討してください。

コードサンプルを見ることからこのセクションを始めましょう。 — これは私たちのService worker で最初に見つかるブロックです

self.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open('v1').then(function(cache) {
      return cache.addAll([
        '/sw-test/',
        '/sw-test/index.html',
        '/sw-test/style.css',
        '/sw-test/app.js',
        '/sw-test/image-list.js',
        '/sw-test/star-wars-logo.jpg',
        '/sw-test/gallery/',
        '/sw-test/gallery/bountyHunters.jpg',
        '/sw-test/gallery/myLittleVader.jpg',
        '/sw-test/gallery/snowTroopers.jpg'
      ]);
    })
  );
});
  1. ここでは Service worker(thisによって)にイベントリスナーを追加して、イベントにExtendableEvent.waitUntil() メソッドをチェーンしています―これはwaitUntil()の内部のコードが成功裡に実行されるまで、サービスワーカーがインストールされないことを保証します。
  2. waitUntil()内で、サイトリソースキャッシュのバージョン1であるv1と呼ばれる新しいキャッシュを生成するために、Caches.open()メソッドを使用します。これは生成されたキャッシュのためにpromiseを返します。ひとたび解決されたら、パラメータとしてキャッシュしたいすべてのリソースのオリジン相対URLの配列を受け取る、生成されたキャッシュのaddAll()を呼び出す関数をコールします。
  3. promiseが拒否された場合やインストールが失敗した場合、workerは何もしません。コードを修正して再度登録にトライすればOKです。
  4. インストールが成功した後、Service worker を起動します。最初に Service worker がインストール、もしくは起動されたときには独特な使い方はありません。しかし Service worker を更新したときにより意義があります(後に続くUpdating your service worker を見てください)。

メモ: localStorageは Service worker キャッシュと同じように動作しますが、同期処理のため、Service worker 内では許可されていません。

メモ: 必要ならば、IndexedDBを Service worker 内でデータ保存のために使用できます。

要求に対するカスタム応答

サイトの資産はキャッシュされたので、Service worker にキャッシュされたコンテンツを使って何かするように指示する必要があります。これはfetchイベントを使って簡単に実現できます。

fetch イベントが発火するたび、指定されたスコープ内の文書とこれらの文書が参照するすべてのリソースを含む、サービスワーカーによって制御されたリソースの取得します(例えば、index.html が画像を埋め込むためにオリジン間要求を行うと、それはサービスワーカーを通過します)。

イベントリスナーをサービスワーカーにアタッチしてから、HTTP応答をハイジャックしてマジックを使って更新するために、イベント上でrespondWith() メソッドを呼び出せます。

self.addEventListener('fetch', function(event) {
  event.respondWith(
    // magic goes here
  );
});

ネットワーク要求した URL と一致するリソースを単純に応答することから始められます。

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request)
  );
});

使用可能なキャッシュと一致する場合、 caches.match(event.request) がキャッシュで利用可能な同等のリソースをネットワークから要求された各リソースに一致するようにできます。マッチングは通常の HTTP 要求と同様に、 URL を経由して行われ、ヘッダを変更します。

オプションについては Request オブジェクトと Responseオブジェクトの詳細を参照してください。詳しくは Fetch API documentation に解説されています。

  1. Response() コンストラクタを使用し、任意の応答を作成できます。この例では、単純なテキストデータが返却されます。

    new Response('Hello from your friendly neighbourhood service worker!');
  2. このより複雑な例では、一般的なHTTP応答を再現するためにヘッダ情報を応答に付与できることを示しています。この例では、応答の種類のみをブラウザーに通知しています。

    new Response('<p>Hello from your friendly neighbourhood service worker!</p>', {
      headers: { 'Content-Type': 'text/html' }
    });
  3. もしキャッシュにリソースがなかった場合は、リソースを取得する一般的な要求である fetch で、使用可能なネットワークから新たにリソースを取得できます。

    fetch(event.request);
  4. もしキャッシュにリソースがなかったり、ネットワークが使用不可能だった場合に、 match() を使用し、要求に対して代替用のページを用意できます。

    caches.match('/fallback.html');
  5. FetchEvent により、返却される Request オブジェクトのプロパティから様々な要求の情報を取得できます。

    event.request.url
    event.request.method
    event.request.headers
    event.request.body

失敗した要求の復旧

caches.match(event.request) はデータがキャッシュされている場合には、うまく動きます。ところで、データがキャッシュされていない場合はどうでしょうか。この場合、失敗時のハンドリングを何も提供しなければ promise は reject して、 マッチしないときにはネットワークエラーが発生します。

幸運なことに、Service worker の promise ベースの構造は、成功に向けたさらなるオプションを設定するためにささやかなことができます。具体的には、以下のようにできます。

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request).then(function(response) {
      return response || fetch(event.request);
    })
  );
});

リソースがキャッシュになかった場合は、ネットワークから要求されます。

私たちが本当に賢いなら、リソースをネットワークから要求するだけではないはずです。後の要求がオフラインでもリソースを扱えるように、キャッシュにもセーブするでしょう。これは、余分な画像がStar Warsギャラリーに追加されたなら、アプリが自動的に画像をとらえてキャッシュすることを意味します。 以下の例はトリックを行っています。

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request).then(function(resp) {
      return resp || fetch(event.request).then(function(response) {
        return caches.open('v1').then(function(cache) {
          cache.put(event.request, response.clone());
          return response;
        });  
      });
    })
  );
});

ここでは、promiseを返すfetch(event.request)と共に、既定のネットワーク要求を返しています。このpromiseが拒否されたとき、caches.open('v1')を使ってキャッシュをとらえる関数を実行して応答します。これもまた、promiseを返します。promiseが拒否されたとき、cache.put() がキャッシュにリソースを追加するために使われます。リソースはevent.requestから捕捉されてから、応答はresponse.clone() でクローンされ、キャッシュに加えられます。クローンはキャッシュに挿入され、オリジナルの要求は呼び出したページに与えるためにブラウザーに返されます。

要求及び応答ストリームは一度しか読み出せないので、応答の複製を作る必要があります。ブラウザーへ応答を返し、かつキャッシュに入れるために、クローンを作成する必要があるのです。ですから、オリジナルはブラウザーに返され、クローンはキャッシュに送られます。それぞれ一度ずつ読み出されます。

これで私たちの抱えるトラブルは、要求がいずれのキャッシュともマッチせず、ネットワークが使用できない場合、いまだ要求が失敗することだけになりました。何が起こってもユーザーが少なくとも何かは取得できるように、既定の代替処理を提供しましょう。

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request).then(function(resp) {
      return resp || fetch(event.request).then(function(response) {
        let responseClone = response.clone();
        caches.open('v1').then(function(cache) {
          cache.put(event.request, responseClone);
        });

        return response;
      });
    }).catch(function() {
      return caches.match('/sw-test/gallery/myLittleVader.jpg');
    })
  );
});

失敗の可能性があるのは新しい画像の更新だけのための代替画像を選択しました。以前確認した、 install イベントリスナーでのインストールに依存している他の画像でも同じことができます。

Service worker の更新

Service worker が以前にインストールされているが、ページの更新や読み込みの時に新しいバージョンの worker が利用できる場合、新しいバージョンはバックグラウンドでインストールされますが、まだ起動しません。まだ古い service worker を使用している読み込まれたページがなくなったら、新しい service worker が起動します。

新しいサービスワーカーで、 install イベントリスナーをこのようなもの (新しいバージョン番号を通知するもの) に更新したくなるでしょう。

self.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open('v2').then(function(cache) {
      return cache.addAll([
        '/sw-test/',
        '/sw-test/index.html',
        '/sw-test/style.css',
        '/sw-test/app.js',
        '/sw-test/image-list.js',
        
        …

        // 新しいバージョンのための新しい他のリソースを入れてください...
      ]);
    })
  );
});

これが発生している間、以前のバージョンはまだ fetch に対して応答します。新しいバージョンは、バックグラウンドでインストールされています。以前の v1 キャッシュを妨げないように、新しいキャッシュを v2 と呼んでいます。

どのページも現在のバージョンを使用していないとき、新しい worker が有効化し、 fetch に応答するようになります。

古いキャッシュの削除

activate イベントを取得することもできます。これは一般的に、実行中の以前のバージョンを破壊するために使われます。たとえば、古いキャッシュを取り除きます。これはディスクスペースがいっぱいになることを防ぐために、もはや不要なデータを削除するのにも役立ちます — それぞれのブラウザーは Service worker が使うために与えられたキャッシュストレージの容量に対して厳しい制限があります。ブラウザーはディスクスペースを管理するために最善を尽くしていますが、オリジンのためのキャッシュストレージを削除するかもしれません。 一般的にブラウザーはオリジンのためのデータをすべて削除するか、オリジンのためのデータを持っていません。

waitUntil() に渡された Promise は、完了するまで他のイベントをブロックするので、新しいキャッシュ上で初めての fetch イベントを取得するときには、クリーンアップ操作が完了していると確信できます。

self.addEventListener('activate', function(event) {
  var cacheKeeplist = ['v2'];

  event.waitUntil(
    caches.keys().then(function(keyList) {
      return Promise.all(keyList.map(function(key) {
        if (cacheKeeplist.indexOf(key) === -1) {
          return caches.delete(key);
        }
      }));
    })
  );
});

開発ツール

Chrome には、現在サービスワーカーのアクティビティやデバイス上のストレージを示す chrome://inspect/#service-workers があり、また、より詳細な情報の表示や、ワーカープロセスを開始/停止/デバッグできる chrome://serviceworker-internals があります。将来的には、不良または存在しない接続をエミュレートするスロットリング/オフラインモードを実装する予定です。これは本当に素晴らしい機能です。

Firefox もサービスワーカーに関する便利なツールを実装し始めています。

  • about:debugging を開くと、サービスワーカーで何が登録されているかを見たり、更新/削除したりすることができます。
  • テストを行う場合、 Firefox 開発者ツール設定で、"HTTP によるサービスワーカーを有効 (ツールボックスを開いたとき)" をチェックすることで、 HTTPS 制約を回避できます。
  • Firefox のカスタマイズオプションで利用できる "Forget" ボタンで、サービスワーカー及びそのキャッシュを消去することができます (バグ 1252998)。

メモ: ローカルでの開発のために、 http://localhost (例えば using me@localhost:/my/app$ python -m SimpleHTTPServer) からアプリのサービスを行うことができます。 Security considerations を参照してください。

関連情報

ドキュメントのタグと貢献者

最終更新者: mdnwebdocs-bot,