アシアルブログ

アシアルの中の人が技術と想いのたけをつづるブログです

Google の Chrome Dev Summit ~ Service Workers に関して ~

GoogleChrome Dev Summit に、先月参加してきました! 
こちらは、Chrome の新機能の紹介や開発者コミュニティーからの要望などをフィードバックする、技術者向けのイベントで、カリフォルニア州のマウンテンビューにある Google の本拠地で開催されました。



ミーティングの内容もさることながら、たくさんの技術者とお会いすることもでき、大変有意義な時間を過ごすことができました。今回が初めてのアメリカへの海外出張でしたが、いい思い出を作ることができました。私たちが滞在したのは、ビクトリア調の建物が立ち並ぶ、サンフランシスコの中でも、ちょっぴり歴史が古い一角でした。この一角は、他にも、壁面に描かれたモダンな絵 ( 落書き? いいえ、グラフィティと呼ばれる、プロの芸術家による創作絵画です! ) が有名なところです。



滞在中は、サンフランシスコらしい?ご飯も楽しむことができました。

Google のミーティングの中で、2 つほど、印象に残った新機能があります。
1 つ目は、Material Design と呼ばれる、新たなデザインの仕様です。2 つ目は、Service Worker API です。どちらも、来年も引き続き、注目すべき機能となるのではないでしょうか。
また、カスタム Web コンポーネントを作成するときに使用する Polymer ( JavaScript ライブラリー ) に関しても、熱い議論がありました。

なかでも、私が興味を持ったのは、Service Worker API の方です。ここでは、こちらの API を中心にお話をします。この API は、オフラインでも、Web ページが継続して動作できるように、ページのキャッシュを行います。各種アセットとアプリのデータをキャッシュするときに使用できます。
よって、基本的には、デスクトップ上でも、携帯端末上でも、Web アプリのデータをキャッシュするとき ( install 時 ) には、このAPI を 使用できます ( install とは、 Service Worker の用語で、キャッシュ処理を開始するときに使用します )。

この API を使用すれば、Web アプリを、より 「 アプリ的 」 ( appy !! ) にできます ( appy とは、Google 技術者の造語です^^。名詞の app に y をつけて、形容詞にしています )。「 アプリ的 」 とは、簡単にいうと、Web アプリだけど、ホーム画面上に置けるなど、ネイティブアプリのように、振る舞うこと・操作することができることを指します。
ネイティブアプリは、ホーム画面上から直接アクセスできたり、オフラインでも実行できるのは周知のとおりです。一方、Web アプリでは、インターネット接続を必要としない処理もありますが、それでも、アセットをダウンロードするときなどには、インターネット接続をしなければならないのが現状です。

Service Workers の現状


API 自体が発展・開発途中なので、正式リリース版のブラウザーではサポートされていませんが、Firefox Nightly や Chrome Canary など、一部のベータ版で、実際に、API を試すことができます。ブラウザー上で Service Workers を有効化する方法は、こちらのページ を参照してください。

最新版の Chrome Canary 上で試したところ、動作が怪しいので、ここでは、Firefox Nightly を使用します。

余談ですが、Chrome 41 から、この API を使用できるようです ( 来年の初旬ごろにリリース )。また、こちらのページ上で、現時点での、主なブラウザーのサポート状況を確認できます。

Service Worker の実装方法


API 自体はシンプルなので、 API のサポート状況を確認した後であれば ( 検証用のライブラリーなどを使用 )、既存の Web アプリにも安全に実装できます ( とはいっても、現時点では、ほとんどのブラウザーでサポートしていませんが... )。



if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/my-app/sw.js', {
    scope: '/'
  }).then(function() {
    console.log('Registration succeeded.');
  }).catch(function(error) {
    console.log('Registration failed with ' + error);
  });
};


上述したように、Service Worker API が利用可能か、確認する処理を最初に行います。
次に、navigator.serviceWorker.register() メソッドを呼び出して、Service Worker を登録します。このメソッドは、Promise ( プロミス/未解決・保留された処理 ) を返します。最初の引数は、ダウンロードして、実行する JavaScript ファイルです。

Service Worker を使用したアセットのキャッシュ方法


Service Worker の登録後に、「 install 」 イベントが発火します。sw.js の中で、このイベントのリスナーを設定します。



// sw.js
this.addEventListener('install', function(event) {
  event.waitUntil(
   caches.create('v1').then(function(cache) {
         return cache.add(
        '/my-app/',
        '/my-app/index.html',
        '/my-app/style.css',
        '/my-app/app.js',
        '/my-app/logo.jpg',
        ... // other assets that we might want to cache.
     );
   })
   );
});



  • caches.create(name) では、Promise を返します。この Promise は、キャッシュ処理が完了したときに、解決 ( 保留の解除 ) します。また、キャッシュに名前を割り当てています。複数のキャッシュを持つことを想定しているため、名前を割り当てることにより、アプリ側での管理が容易になります。

  • cache.add() を使用して、アセットをキャッシュに追加します。



キャッシュの使用方法


ここまでの処理で、キャッシュの作成、アセットのキャッシュへの追加が完了しました。そこで、ブラウザーに対して、外部へアセットをリクエストする代わりに、キャッシュ内部のデータを使うように、命令してみましょう。

Service Worker API では、「 fetch 」 イベントを使用して、リクエストされたリソースを取得します。シンプルな処理ですが、キャッシュされたアセットがあれば、それを返してくれます。



// sw.js
this.addEventListener('fetch', function(event) {
  event.respondWith(
    // this will respond with what is in the cache.
    caches.match(event.request);
  );
});


cache.match() では、例外処理時に使用できる Promise を返します。以下の例では、キャッシュされたアセットがない場合、通常のリクエストを使用した、リソースの取得を行います。



// sw.js
this.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request).catch(function() {
      return event.default();
    });
  );
});


上述の処理に加え、動的に、リソースをキャッシュすることも可能です。キャッシュ処理を段階的に行い、リソースを節約しつつ、オフライン時のアプリの実行に備えることもできます。また、クロスドメインからでもリソースをキャッシュできるため、たとえば、CDN のコンテンツなど、リモートのアセットもキャッシュできます。

他の処理の記法に関しては、こちらのページ をご確認ください。

使用勝手もさることならが、オフラインでも Web アプリを実行できる機能を提供してくれる、この API は、Web アプリの可能性を広げてくれるのではないでしょうか。今後も、目が離せませんね。今回は、Service Worker API の話を主にしましたが、今後の大きな流れとして、ネイティブ側が使用していた機能・リソースが、より外側(ブラウザー側)に解放され、ブラウザー上で動作するアプリもネイティブライクなものになっていくのではないしょうか。
そんな事を感じさせてくれるミーティングでした。