2014-12-17

Chrome40にservice workersがきた

Chrome 40になってService workersが来たらしい。デモを動かしてみたり自分で書いてみたりして紹介記事でも書こうかなと思っていたが、 +Hajime Morrita はRebuild.fmに出演して紹介してしまったし、ほかにもすでにいくらか紹介記事が出始めてきた(たとえばhttp://qiita.com/kinu/items/2abd61b4390f9bbaffc9)。賑やかしにと自分もスクリーンキャストの動画も撮ってみた。

ここではデモの補足として、Service workersってどんなものなのかをふんわり考えてみる。

Service workers とは

って項目を書いたのだがこの説明が難しい……。新しいウェブのAPI、だけだとだからなにって感じ。Service workersはweb workersの一種なのだが、って説明しはじめると泥沼に嵌りそうだ。

Service workersでブラウザの機能として大きいと思うのは、タブと独立して動くJSの実行環境を手に入れるということだと思う。

Web workersというのはJSのスレッドみたいなものなので、普通にタブのなかのスクリプトから作られるし、タブが閉じられると消える。複数のタブで共有されるshared workerというのもいるけれど、これもタブが全部閉じたら消える。どちらもタブに従属している。

それと違い、Service workerはブラウザにインストールされる。さいしょにインストールするには、登録するページを読まないといけないけれど、登録が済んでしまえばページとは関係なく動作する(細かい補足になるが、動作するといっても、つねにプロセスを起動しっぱなしにするということではない。必要に応じて起動する)。で、ウェブページやウェブアプリと協調動作していろんなうれしい機能を提供する。

そういうバックグラウンドサービスというのは、実はこれまでブラウザにはなかった。拡張機能によってそういうのはなんとかしてきた歴史があったが、そうした無理を解消しつつ標準化していくのがService workersなのかなというのが個人的な認識だ。

Service workersの役目とスコープ

Service workerはウェブのリクエストを取り扱う。そういう意味では、少し前に話題になったフェッチAPIと関係がある。

リクエストの取扱範囲はスコープで制御される。デフォルトは登録元のサイトのトップで、これはようするにサイト全体がひとつのウェブアプリになっていてservice workerはそのウェブアプリに対して動作するということが念頭にあるのかなと思う。ただもちろん、登録時のオプショナル引数でそこからサブディレクトリに制限をかけることもできる。

取り扱い範囲のフェッチリクエストが来ると、まずService workersのfetchイベントハンドラを駆動する。Service workerはそのイベントハンドラを勝手に横取りして自分で勝手にレスポンスを作ってもよい(これがデモでやってみた事例)。なんにもしなければ普通のリクエストに戻っていく。

ただ、スクリーンキャストのなかでぶつぶつしゃべったように、ふつうはダミーデータを作ったりすることは少ないはずだ(ネットワークがつながってないときにエラーメッセージを渡すというのはあるかも)。ありがちなサンプルとしては、
  • 画像やCSSなど静的なデータをキャッシュしておき、ネットワークなしでもページをロードできるようにする(オフライン化)
  • twitterのフィードフェッチなど、複数タブを開いていると無駄になりそうなコネクションの一本化
といったところだろう。この辺はService worker専用のキャッシュAPIなどを使うことになる。と思う。

アプリのオフライン化についてはapplication cacheというAPIがこれまでもあったのだけど、残念ながらいろんな事情からマイナーな仕様にとどまっている。application cacheと比べると、簡単な事例についてはService workersのほうが書く量は増えることになるが、柔軟性が圧倒的に高く管理しやすいので、いろいろ考えるとService workersのほうがいいんじゃないかという気がする。application cacheのつらみはこの記事でよく解説されている(らしい。ごめん読んでない)。

Service workersとevent pages

Service workersの動作や仕様を眺めているとChrome拡張機能のevent pagesと近しい印象を受ける。

Chrome拡張機能にはいろんな機能があるんだけど、background pagesというのがあった。拡張機能はページにくっついたり、ポップアップになったり、自前でタブを開いたりするのだが、ユーザに見える部分とは別にいろんな処理をまとめるバックエンドがあるといろいろ便利で、それがbackground pagesとなる。拡張機能やChromeアプリを作るとき、ユーザに見える部分は単にHTML/CSS/JSでシンプルに作って、イベントハンドラからbackground pagesにメッセージを投げていろんな処理や拡張機能用のAPI呼び出しを一本化したり、といったことに使われてきた。

background pagesは便利だったんだけど、問題がひとつあった。というのは、拡張機能をインストールするとそのbackground pagesのプロセスがずーっと起動しっぱなしになってリソースを無駄遣いするのだ。そこで導入されたのがevent pagesで、ようするに「background pagesなんだけど、ブラウザは適当にプロセス止めてもいいっすよ」というフラグをつけたものと思えばいい。

event pagesはインストール時や初回起動時に実行され、イベントハンドラを登録する。そういうイベントが発生したときや、また拡張機能のUIからbackground pageにメッセージを投げようとすると、プロセスが起こってメッセージを処理し、しばらくするとプロセスが勝手に止まる。

Service workersは、このevent pagesをウェブ流にうまく表現したもの、ということができると思う。Chromeの場合、プロセスを適当なタイミングで閉じて、フェッチが発生したりページからpostMessageしたときだけプロセスが起こるというのもいっしょだ(よく知らないけど実装もけっこう流用できていると思う)。拡張機能を書いてて便利だったことがいろいろできるようになる。はずである。

Service workersの現状と今後

最初に書いたようにChromeでは40から使えるようになった(39でもコマンドラインフラグを指定すれば使えるようになっていたが、フラグフリップしたようだ)。ほかにサポートを表明しているのはFirefoxだが、こちらはフラグがないとまだ動かないらしい。Operaはよく知らないけど、なかみはBlinkなので対応は進むと思われる。それ以外のブラウザは対応を表明していない(Firefoxが支持しているというのは面白いところなんだけど……まあそういう深読みはここでは避ける)。

そういう状況なので、いますぐService workersを使わないとヤバイ、とか、もう準備万端なのでバリバリ使うべき、という話とは程遠い。が、Service workersはキャッシュやオフライン化をオプショナルに、つまり「できる環境でだけうれしい」程度の機能として提供しやすいという面がある。そういう面では、Chromeの安定版で使えるようになるあと数週間後には、触ってみてどんなもんなのか試してみるぐらいの価値はあると思う。

ただ仕様はまだドラフト段階なので、細部は変わる可能性はある。詳しくはgithubのissueにて熟知すべし。なのかな。

なお、Service workersの仕様は、それなりに長いんだけど、機能としては比較的シンプルだということに気づく。ようするに、基本的にはフェッチイベントを受け取ってキャッシュしたデータをサーブする、という機能に特化していてそれ以外の用途にはあんまり向いていない。ほかにもこんなことができたら面白そうなんだけど、という夢みたいな話はあまり入っていない。

たとえばサーバからプッシュ通信を受けつけることができるとしよう。Facebookで誰かがメッセージを送ったらサーバプッシュが届いて、それをservice workersが受けて、タブが開いてなくても通知が出せる、となったら、かなり夢が広がる気がする。Google calendarの通知とか、いいかげんタブ開いてなくても教えてほしい。そういうのはまさに拡張機能が受け持っていた機能だったけど、ブラウザごとに作るのは不毛すぎる。

ほかにも、拡張機能のevent pagesにはchrome.alarmsというAPIがあって、定期的に処理するようなイベントなんだけど、これもService workersには含まれていない。1分ごとにフェッチして変化があったらページに通知して……みたいなやつ。window.setIntervalがあればいいじゃん、て思うかもしれないけれど、それは普通のJSのAPIなのでプロセスが止まったら不都合が生じてしまう(コードの意味が変わってしまう)ため、プロセスを止められなくなる。別なAPIで対応してあげる必要がある。

実はこの辺も議論されている。プッシュ通知はpush APIという別なAPIが提案されているし、定期的にservice workerを起こすというのはbackground sync APIという仕様になるようだ。

というあたりの状況からすると、service workersはいわば導入編であって、これを軸にこれからいろんな面白機能が入ってくるのかなと期待している。そういう意味でもservice workersはいろいろ注目のAPIだと思う。

謝辞

このブログの記事、先週頭ぐらいに書いていたドラフトがあったのだが、いろいろあって完全に書き直してしまった。もとの文章と全然違っちゃったけどそちらにコメントや訂正をいただいた+Eiji Kitamura+Hiroki Nakagawaありがとうございました。むろん、間違いや勘違いの責任は向井にあります。

参考資料
  1. Chrome 40 で今すぐ ServiceWorker を試す: http://qiita.com/kinu/items/2abd61b4390f9bbaffc9 
  2. Service Workers spec: http://slightlyoff.github.io/ServiceWorker/spec/service_worker/
  3. Service workers samples: https://github.com/GoogleChrome/samples/tree/gh-pages/service-worker
  4. AppCache: https://html.spec.whatwg.org/multipage/browsers.html#offline
  5. Chrome extensions event pages: https://developer.chrome.com/extensions/event_pages
  6. push API: https://w3c.github.io/push-api/
  7. Background sync: https://github.com/slightlyoff/BackgroundSync/blob/master/explainer.md