これは実験的な機能です。本番で使用する前にブラウザー実装状況をチェックしてください。

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

サービスワーカーの前提条件

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

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

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

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

サービスワーカーを始めるための設定

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

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

基本構造

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

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

以下の図は、利用可能なサービスワーカーのイベントの概要を示しています。

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

Promise

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

Promise は多くのすばらしいことを行うことができます。しかし今は知っておくべきことは、何かが Promise を返したとき、末尾に .then() を繋げることによって、成功時や失敗時などのコールバックをその中に含めることができ、失敗時のコールバックを含めたいときは最後に .catch() を挿入することもできるということです。

昔ながらの同期的なコールバック構造と、それに相当する非同期的な 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 テストの例のソースコードを見てください。このコードが無事動いていることにも注目してください)。

註: 実際のサービスワーカーの導入では非推奨の 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 についてのより多くの発見をすることができます。

サービスワーカーのデモ

サービスワーカーの登録とインストールについてのとても基本的なデモンストレーションをするために、私たちは 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 の動き方です。

サービスワーカーに入る

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

workerを登録する

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

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 コンテクストで実行されるサービスワーカーを登録しているため、 DOM アクセスは含まれていません。続いて、通常ページの外側のサービスワーカーでロードを制御するためにコードを実行します。

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

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

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

なぜサービスワーカーの登録に失敗するのか

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

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

他のメモです。

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

インストールと起動: キャッシュを配置する

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

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

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

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

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. ここではサービスワーカー(thisによって)にイベントリスナーを追加して、イベントにExtendableEvent.waitUntil() メソッドをチェーンしています―これはwaitUntil()の内部のコードが成功裡に実行されるまで、サービスワーカーがインストールされないことを保証します。
  2. waitUntil()内で、サイトリソースキャッシュのバージョン1であるv1と呼ばれる新しいキャッシュを生成するために、Caches.open()メソッドを使用します。これは生成されたキャッシュのためにpromiseを返します。ひとたび解決されたら、パラメータとしてキャッシュしたいすべてのリソースのオリジン相対URLの配列を受け取る、生成されたキャッシュのaddAll()を呼び出す関数をコールします。
  3. promiseが拒否された場合やインストールが失敗した場合、workerは何もしません。コードを修正して再度登録にトライすればOKです。
  4. インストールが成功した後、サービスワーカーがアクティベートします。最初にサービスワーカーがインストール/アクティベートされたときには独特な使い方はありませんが、サービスワーカーを更新したときにより意義があります(後に続くUpdating your service worker を見てください)。

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

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

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

サイトの資産はキャッシュされたので、サービスワーカーにキャッシュされたコンテンツを使って何かするように指示する必要があります。これは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

失敗した要求の復旧

サービスワーカー cacheに一致する場合、caches.match(event.request) は優れていますが、マッチしない場合はどうでしょう?失敗時のハンドリングを何も提供しなければ、promiseはrejectして、 マッチしないときにはネットワークエラーが発生します。

幸運なことに、サービスワーカーの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 イベントリスナーでのインストールに依存している他の画像でも同じことができます。

サービスワーカーの更新

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

新しいサービスワーカーで、 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 と呼んでいます。

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

古いキャッシュの削除

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

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

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

  event.waitUntil(
    caches.keys().then(function(keyList) {
      return Promise.all(keyList.map(function(key) {
        if (cacheWhitelist.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 を参照してください。

仕様書

仕様書 状態 備考
Service Workers 草案 初回定義。

ブラウザーの対応

現在、互換性データを可読形式の JSON フォーマットに置き換えているところです。 この互換性一覧は古い形式を使っており、これに含まれるデータの置き換えが済んでいません。 手助けしていただける場合は、こちらから!
機能 Chrome Edge Firefox (Gecko) Internet Explorer Opera Safari (WebKit)
基本対応 40.0 16[2] 33.0 (33.0)[1] 未サポート 24 11.1
機能 Android Webview Chrome for Android Firefox Mobile (Gecko) Firefox OS IE Phone Opera Mobile Safari Mobile
基本対応 未サポート 40.0 (有) (有) 未サポート (有) 未サポート

[1] サービスワーカー (及び Push) は Firefox 45 Extended Support Release (ESR.) では無効になりました。

[2] Microsoft Edge の試験的な対応が EdgeHTML 16 でフラグに隠されて行なわれています。

関連情報

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

最終更新者: mononeco,