著者について
Lyza Danger Gardnerは、開発者です。 2007年にオレゴン州ポートランドを拠点とするモバイルウェブスタートアップのCloud Fourを共同設立して以来、彼女は、モバイルアプリケーションの開発で自分自身を苦しめ、スリリングにさせてきました…More aboutLyza↬
- 23 min read
- Coding,JavaScript,Techniques,Service Workers
- Saved for offline reading
- Share on Twitter.com
- コーディング、JavaScript、テクニック、サービスワーカー。 LinkedIn
初期のサービス ワーカー API は、現在いくつかの一般的なブラウザで出荷されており、その宣伝や興奮には事欠かないでしょう。 クックブックやブログ投稿、コード スニペット、ツールなどがあります。 しかし、新しい Web のコンセプトを徹底的に学びたい場合、袖をまくり上げ、飛び込んで、ゼロから何かを構築することが理想的であることがよくあります。
今回遭遇した衝突や傷、不具合やバグには、利点があります。 今、私はサービス ワーカーをよりよく理解しており、運が良ければ、私が新しい API で作業するときに遭遇した頭痛の種を避ける手助けができるかもしれません。 つまり、
- Web サイトをオフラインで機能させる、
- 特定のアセットに対するネットワーク要求を減らすことによりオンライン パフォーマンスを向上させる、
- オフライン フォールバック体験をカスタマイズして提供する、といった機能です。
始める前に、これを可能にした 2 人の人物に謝意を表したいと思います。 まず、私自身のコードの出発点となった、彼自身の Web サイトでのサービス ワーカーの実装について、Jeremy Keith に多大な恩義を感じています。 彼の最近の投稿に触発され、現在進行中のサービスワーカーの経験を記述しました。 実際、私の仕事は非常に大きく派生しており、以前の投稿での Jeremy の励ましがなければ、それについて書くことはなかったでしょう。
So if you decide to play around with Service Workers, please, please share your experience.
Secondly, all sorts of big old thanks to Jake Archibald for his excellent technical review and feedback.
サービス ワーカー仕様の作成者および伝道者の 1 人が、あなたを正してくれるのは嬉しいことです!
What Is A Service Worker?
サービス ワーカーは、Web サイトとネットワークの間に立って、特に、ネットワーク要求を傍受してさまざまな方法でそれに対応する能力を与えてくれるスクリプトです。 以前は、この管理は主にブラウザの特権でした。 もしブラウザがネットワークにアクセスできなければ、「オフラインです」というメッセージが表示されるはずです。 資産のローカル キャッシュを促進するために使用できるテクニックはありましたが、多くの場合、ブラウザが最終決定権を持っていました。
これはオフラインのユーザーにとってあまり良い経験ではなく、Web 開発者はブラウザ キャッシュをほとんど制御できないままでした。 表向きは、Web サイトやアプリがオフラインで動作するように、異なるアセットをどのように処理すべきかを指示することができます。 しかし、AppCache のシンプルに見える構文は、その根本的な不可解な性質と柔軟性の欠如を裏付けていました。
初期のサービス ワーカー API は、AppCache が行ったこと、さらに多くのことを行うことができます。 しかし、最初は少し大変に見えます。 仕様は重く、抽象的な読み物であり、多数の API がそれに従属するか、さもなければ関連しています。 cache
や fetch
などです。 サービスワーカーは多くの機能を包含しています。プッシュ通知や、まもなくバックグラウンドでの同期も可能になります。 AppCache と比較すると、それは…複雑に見えます。
AppCache (ところで、これはなくなりつつあります) は学ぶのは簡単ですが、その後のすべての瞬間がひどい (私の意見) のに対して、サービス ワーカーは初期の認識投資がより多く必要ですが、強力で便利で、物事を破壊しても概して問題から脱出することができます。 そのファイルでは、あなたが知っていて好きなように JavaScript を書くことができますが、心に留めておくべきいくつかの重要なことがあります。
サービス ワーカー スクリプトは、制御するページとは別のブラウザのスレッドで実行されます。 ワーカーとページの間で通信する方法はありますが、ワーカーは別のスコープで実行されます。 つまり、たとえば、それらのページの DOM にアクセスすることはできません。 これはまったく正確ではありませんが、自分自身を混乱から守るための大まかな比喩として役立ちます。 非同期 API を使用する必要があります。 たとえば、サービス ワーカーでは localStorage
を使用できません (localStorage
は同期 API です)。 おかしなことに、このことを知っていても、後ほど説明するように、私は違反する危険を冒すことができました。
Registering a Service Worker
サービス ワーカーを有効にするには、登録します。 この登録は、サービスワーカーの外部から、Web サイトの別のページまたはスクリプトによって行われます。 私の Web サイトでは、グローバル site.js
スクリプトがすべての HTML ページに含まれています。 そこからサービスワーカーを登録します。
サービスワーカーを登録するとき、(オプションで)どのスコープに適用すべきかも指示します。 サービスワーカーに Web サイトの一部 (たとえば '/blog/'
) のみを処理するように指示することも、私のように Web サイト全体 ('/'
) に対して登録することもできます。
Service Worker Lifecycle And Events
A service worker does the bulk of its work by listening for relevant events and responding them in useful ways.A service worker は、関連イベントをリッスンし、それに対し有用な方法で対応します。 サービス ワーカーが登録され、ダウンロードされると、バックグラウンドでインストールされます。 サービス ワーカーは install
イベントをリッスンし、この段階に適したタスクを実行できます。
このケースでは、install
状態を利用して、後でオフラインで利用可能にすることが分かっている資産の束を事前にキャッシュしたいと思います。 これは、サービス ワーカーがその scope
内で物事をコントロールできるようになったことを意味し、その役割を果たすことができます。 activate
イベントは、新しいサービス ワーカーにとってはあまり刺激的ではありませんが、サービス ワーカーを新しいバージョンで更新するときに、どのように役に立つかを見ていきます。
一度インストールとアクティブ化が完了すると、サービス ワーカーの更新バージョンがダウンロードされ登録されるまで、再びアクティブ化は行われません。 たとえば、同期イベントや通知イベントなどです。
追加単位または余暇の楽しみとして、サービスワーカーが実装するインターフェイスについてもっと読むことができます。
The Service Worker’s Promise-Based API
The service worker API makes heavy use of Promises
.This is by implementing these interfaces that service workers get the bulk of their events and their much of extended functionality.
getAnAnswerToADifficultQuestionSomewhereFarAway() .then(answer => { console.log('I got the ${answer}!'); }) .catch(reason => { console.log('I tried to figure it out but couldn't because ${reason}');});
getAnAnswer…
関数は Promise
を返し、それは最終的に私たちが探している answer
によって満たされる、または解決されることを (私たちは) 望んでいます。 その後、その answer
は連鎖した then
ハンドラ関数に渡すことができます。または、残念ながら目的を達成できなかった場合、Promise
は拒否され、catch
ハンドラ関数はこれらの状況を処理することができます。
注意: サービス ワーカーのサンプル コードで特定の ECMAScript6 (または ES2015) 機能を使用していますが、これはサービス ワーカーをサポートするブラウザがこれらの機能もサポートしているためです。 具体的には、矢印関数とテンプレート文字列を使用しています。
Other Service Worker Necessities
また、サービス ワーカーは動作するために HTTPS を必要とすることに留意してください。 このルールには、重要で便利な例外があります。 サービス ワーカーは安全でない http
上で localhost
のために動作し、ローカル SSL を設定するのが面倒な場合があるので、これは救いです。 これは、将来ブラウザに登場する楽しい新機能のほとんどすべてが SSL の使用を必要とするため、皆さんに検討していただきたいことです。
これからまとめるものはすべて、今日 Chrome で動作します (私はバージョン 47 を使用しています)。 今にも Firefox 44 が出荷され、サービス ワーカーをサポートします。 Is Service Worker Ready? では、さまざまなブラウザでのサポートに関する詳細な情報を提供しています。
Registering, Installing And Activating A Service Worker
さて、いくつかの理論に対処したところで、サービス ワーカーの組み立てを開始しましょう。
サービス ワーカーをインストールしてアクティブにするには、install
と activate
のイベントをリッスンして、それらに対応します。 serviceWorker.js
:
self.addEventListener('install', event => { // Do install stuff});self.addEventListener('activate', event => { // Do activate stuff: This will come later on.});
Registering Our Service Worker
ここで、サービス ワーカーを使用するように Web サイトのページに指示する必要があります。
私の site.js
:
if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/serviceWorker.js', { scope: '/' });}
Pre-Caching Static Assets During Install
私はインストール段階を使って、Web サイトのいくつかの資産を事前にキャッシュしたいと思います。
- Web サイトの多くのページで使用されるいくつかの静的アセット (画像、CSS、JavaScript) を事前にキャッシュすることにより、その後のページ読み込み時にネットワークから取得する代わりに、キャッシュからこれらを取得して読み込み時間を短縮することができます。
これを行う手順は次のとおりです。
install
イベントを待機させ、event.waitUntil
を使用して必要なことを完了するまで完了しないようにします。 プログレッシブ Web アプリの用語では、これらの資産は「アプリケーション シェル」を構成します。
/serviceWorker.js
では、install
ハンドラーを展開します。 caches
にはいくつかの便利なメソッドがあります。たとえば open
や delete
です。
ここで、Promises
が動作しているのを見ることができるでしょう。 caches.open
は static
キャッシュを正常に開くと、cache
オブジェクトに解決する Promise
を返します。addAll
はまた、渡されたすべてのアイテムがキャッシュに格納されると解決する Promise
を返します。
私は event
に、私のハンドラー関数が返す Promise
が正常に解決するまで待つように言っています。 そうすれば、インストールが完了する前に、それらの事前キャッシュ項目のすべてがソートされることを確認できます。
コンソールの混乱
Stale Logging
おそらくバグではありませんが、確かに混乱があります。 サービス ワーカーから console.log
を実行すると、Chrome は、後続のページ要求でそれらのログ メッセージをクリアするのではなく、再表示しつづけます。
たとえば、install
ハンドラーに log
ステートメントを追加してみましょう。
self.addEventListener('install', event => { // … as before console.log('installing');});
正常な場合のエラー
もう 1 つの奇妙なことは、サービス ワーカーがインストールされて有効になると、その範囲内の任意のページに対するその後のページ読み込みで、常にコンソールに 1 つのエラーが発生することです。 何か間違ったことをしているのかと思いました。
ここまでで達成したこと
サービス ワーカーは install
イベントを処理し、いくつかの静的アセットを事前にキャッシュしています。
serviceWorker.js
の内容は GitHub にあります。
Fetch Handling With Service Workers
これまでのところ、このサービス ワーカーには具体的な install
ハンドラがありますが、それ以上のことは何もしていません。 サービス ワーカーの魔法は、fetch
イベントがトリガーされたときに、本当に起こるでしょう。 異なるネットワーク戦略を使用することにより、常にネットワークから特定のアセットを取得しようとするようブラウザに指示することができ (重要なコンテンツが新鮮であることを確認します)、一方で静的アセットにはキャッシュされたコピーを優先させ、ページ ペイロードを非常にスリムにすることができます。
ブラウザがこのサービス ワーカーのスコープ内のアセットを取得しようとするときはいつでも、serviceWorker.js
:
self.addEventListener('fetch', event => { // … Perhaps respond to this fetch in a useful way?});
に eventListener
を追加することにより、それを通知することができます。 これらのフェッチに対するブラウザの応答を選択的に処理することができます。
ある資産に対して fetch
イベントが発生したとき、最初に判断したいことは、このサービス ワーカーが与えられたリソースの取得に干渉すべきかどうかです。
最終的に、serviceWorker.js
:
self.addEventListener('fetch', event => { function shouldHandleFetch (event, opts) { // Should we handle this fetch? } function onFetch (event, opts) { // … TBD: Respond to the fetch } if (shouldHandleFetch(event, config)) { onFetch(event, config); }});
関数は与えられたリクエストを評価し、応答を提供すべきか、ブラウザにデフォルトの処理をさせるべきかを決定します。
Why Not Use Promises?
サービス ワーカーのプロミスへの偏愛を維持するために、私の fetch
イベント ハンドラの最初のバージョンは次のようなものでした:
self.addEventListener('fetch', event => { function shouldHandleFetch (event, opts) { } function onFetch (event, opts) { } shouldHandleFetch(event, config) .then(onFetch(event, config)) .catch(…);});
論理的には見えますが、私はプロミスでいくつかの新人の間違いを犯していました。 私は当初からコードの匂いを感じていたのですが、Jakeが私のやり方の誤りを正してくれたのです。 (教訓: いつものように、コードが間違っていると感じたら、それはおそらくそうです。)
Promise rejections は、「気に入らない答えが返ってきた」ことを示すために使用するべきではありません。 代わりに、拒絶は、”ああ、くそ、答えを得るために何かが間違っていた” を示すべきです。
Criteria for Valid Requests
Right, back to determining whether a given fetch request is applicable for my service worker. 私のサイト固有の基準は次のとおりです。
- 要求された URL は、キャッシュまたは応答したいものを表す必要があります。
- リクエストの HTTP メソッドは
GET
でなければなりません。 - リクエストは、私のオリジン (
lyza.com
) からのリソースでなければなりません。serviceWorker.js
:function shouldHandleFetch (event, opts) { var request = event.request; var url = new URL(request.url); var criteria = { matchesPathPattern: !!(opts.cachePathPattern.exec(url.pathname), isGETRequest : request.method === 'GET', isFromMyOrigin : url.origin === self.location.origin }; // Create a new array with just the keys from criteria that have // failing (i.e. false) values. var failingCriteria = Object.keys(criteria) .filter(criteriaKey => !criteria); // If that failing array has any length, one or more tests failed. return !failingCriteria.length;}
もちろん、ここでの基準は私自身のものであり、サイトによって異なるでしょう。
event.request
はRequest
オブジェクトで、フェッチ ハンドラーにどのように動作させたいかを評価するために見ることができるあらゆる種類のデータを持っています。Trivial note: ハンドラー関数に
opts
として渡されるconfig
が出現したことに気づいたら、それはよくわかりました。 再利用可能なconfig
のような値を除外し、サービス ワーカーのトップレベル スコープにconfig
オブジェクトを作成しました。var config = { staticCacheItems: , cachePathPattern: /^\/(?:(20{2}|about|blog|css|images|js)\/(.+)?)?$/};
Why Whitelist?
なぜこの正規表現に一致するパスのみをキャッシュするのかと疑問に思うかもしれません:
/^\/(?:(20{2}|about|blog|css|images|js)\/(.+)?)?$/
… いくつかの理由:
- サービス ワーカー自体をキャッシュしたくない。
- ウェブサイトをローカルに開発しているとき、キャッシュしたくないものがリクエストされることがあります。 たとえば、私は
browserSync
を使用していますが、これは私の開発環境で関連する要求の束をキックオフします。 そんなものキャッシュしたくないよ!」と。 キャッシュしたくないものをすべて考えようとすると、面倒で大変なことになります(言うまでもなく、サービスワーカーの設定にそれを明記しなければならないのは少し変です)。
Fetch ハンドラを書く
さて、該当する
fetch
リクエストをハンドラに渡す準備ができています。onFetch
関数は、- どのようなリソースが要求されているか、
- この要求をどのように満たすべきかを決定する必要があります。 要求されているリソースの種類は何か。
HTTP Accept
ヘッダーを見て、要求されているアセットの種類についてのヒントを得ることができます。function onFetch (event, opts) { var request = event.request; var acceptHeader = request.headers.get('Accept'); var resourceType = 'static'; var cacheKey; if (acceptHeader.indexOf('text/html') !== -1) { resourceType = 'content'; } else if (acceptHeader.indexOf('image') !== -1) { resourceType = 'image'; } // {String} cacheKey = resourceType; // … now do something}
整理された状態を保つために、異なる種類のリソースを異なるキャッシュに格納したいと思います。 これにより、後でこれらのキャッシュを管理できるようになります。 キャッシュ API には意見がありません。
2. Fetch
に応答する 次に
onFetch
が行うことは、fetch
イベントをインテリジェントなResponse
でrespondTo
処理することです。function onFetch (event, opts) { // 1. Determine what kind of asset this is… (above). if (resourceType === 'content') { // Use a network-first strategy. event.respondWith( fetch(request) .then(response => addToCache(cacheKey, request, response)) .catch(() => fetchFromCache(event)) .catch(() => offlineResponse(opts)) ); } else { // Use a cache-first strategy. event.respondWith( fetchFromCache(event) .catch(() => fetch(request)) .then(response => addToCache(cacheKey, request, response)) .catch(() => offlineResponse(resourceType, opts)) ); }}
Careful With Async!
このケースでは、
shouldHandleFetch
は非同期なことは何もしていないし、onFetch
もevent.respondWith
の時点まではそうしていない。 それ以前に非同期的なことが起こっていたら大変なことになる。event.respondWith
はfetch
イベントが発生してから制御がブラウザに戻るまでの間に呼ばれなければならない。event.waitUntil
も同様である。 基本的に、イベントを処理する場合、すぐに(同期的に)何かを行うか、非同期的なものが完了するまで待機するようにブラウザに指示します。 ネットワーク優先の戦略の実装fetch
リクエストに応答するには、適切なネットワーク戦略を実装する必要があります。 HTML コンテンツ (resourceType === 'content'
) のリクエストに応答する方法を詳しく見てみましょう。if (resourceType === 'content') { // Respond with a network-first strategy. event.respondWith( fetch(request) .then(response => addToCache(cacheKey, request, response)) .catch(() => fetchFromCache(event)) .catch(() => offlineResponse(opts)) );}
ここで、コンテンツのリクエストを満たす方法は、ネットワーク優先戦略です。 HTML コンテンツは私の Web サイトの中核的な関心事であり、頻繁に変更されるので、常にネットワークから新鮮な HTML ドキュメントを取得するようにしています。
では、この手順を説明します。 ネットワークから取得してみる
fetch(request) .then(response => addToCache(cacheKey, request, response))
ネットワーク リクエストが成功したら (すなわち、約束が解決したら)、先に進み、適切なキャッシュ (
content
) に HTML ドキュメントのコピーをため込みます。function addToCache (cacheKey, request, response) { if (response.ok) { var copy = response.clone(); caches.open(cacheKey).then( cache => { cache.put(request, copy); }); return response; }}
Responses may be only once.
We need to do two things with the
response
we have:- cache it,
- respond to the event with it (i’s it return).
But
Response
objects may be only once.This uses a read-through Caching.We are not do two things with the
response
with theresponse
with theresponse
with the event is used. クローンを作成することにより、キャッシュの使用のためのコピーを作成することができます。var copy = response.clone();
悪い応答をキャッシュしないでください。 私がしたのと同じ間違いをしないでください。 私のコードの最初のバージョンはこの条件を持っていなかった:
if (response.ok)
キャッシュに 404 やその他の悪い応答が残ってしまうのはかなりすごいことです! ハッピーなレスポンスだけをキャッシュします。
2. キャッシュからの取得を試みる
ネットワークから資産を取得することに成功したら、完了です。 しかし、成功しなかった場合、オフラインであるか、またはネットワークが侵害されている可能性があります。
fetch(request) .then(response => addToCache(cacheKey, request, response)) .catch(() => fetchFromCache(event))
ここで、
fetchFromCache
関数を使用します:function fetchFromCache (event) { return caches.match(event.request).then(response => { if (!response) { // A synchronous error that will kick off the catch handler throw Error('${event.request.url} not found in cache'); } return response; });}
注意:
caches.match
でチェックするキャッシュを指定しないで、一度にすべてをチェックします。3. オフライン フォールバックを提供する
ここまでやってもキャッシュに応答できるものがない場合、可能であれば、適切なオフライン フォールバックを返します。 HTMLページの場合、これは
/offline/
からキャッシュされたページである。 これは、ユーザーにオフラインであることと、ユーザーが求めているものを満たすことができないことを伝える、適度に整えられたページです。fetch(request) .then(response => addToCache(cacheKey, request, response)) .catch(() => fetchFromCache(event)) .catch(() => offlineResponse(opts))
そして、これが
offlineResponse
関数です。 キャッシュ ファースト戦略の実装HTML コンテンツ以外のリソースのフェッチ ロジックは、キャッシュ ファースト戦略を使用します。 そのため、最初にキャッシュをチェックして、ネットワークの往復を回避します。
event.respondWith( fetchFromCache(event) .catch(() => fetch(request)) .then(response => addToCache(cacheKey, request, response)) .catch(() => offlineResponse(resourceType, opts)));
ここでの手順は次のとおりです。
- キャッシュから資産を取得しようとする。
- それができない場合、ネットワークから (read-through キャッシュで) 取得してみる。
Offline Image
offlineResource
関数を実行すると、オフラインのフォールバックとして “Offline” というテキスト付きの SVG 画像を返すことができます:function offlineResponse (resourceType, opts) { if (resourceType === 'image') { // … return an offline image } else if (resourceType === 'content') { return caches.match('/offline/'); } return undefined;}
そして、
config
:var config = { // … offlineImage: '<svg role="img" aria-labelledby="offline-title"' + 'viewBox="0 0 400 300" xmlns="http://www.w3.org/2000/svg">' + '<title>Offline</title>' + '<g fill="none" fill-rule="evenodd"><path fill=>"#D8D8D8" d="M0 0h400v300H0z"/>' + '<text fill="#9B9B9B" font-family="Times New Roman,Times,serif" font-size="72" font-weight="bold">' + '<tspan x="93" y="172">offline</tspan></text></g></svg>', offlinePage: '/offline/'};
CDN に注意
フェッチ処理をオリジンに制限している場合、CDN に注意する必要があります。 最初のサービス ワーカーを構築したとき、ホスティング プロバイダーがアセット(画像とスクリプト)を CDN にシャードして、ウェブサイトのオリジン(
lyza.com
)から提供されなくなったことを忘れていました。 おっと! うまくいかなかった。 結局、影響を受けるアセットの CDN を無効にしました (ただし、もちろんこれらのアセットは最適化します!)。最初のバージョンの完了 サービス ワーカーの最初のバージョンが完了しました。 最適化された応答で該当するフェッチに応答し、キャッシュされたリソースとオフライン時にオフライン ページを提供できるinstall
ハンドラーと詳細なfetch
ハンドラーを持っています。フェッチ処理 (
serviceWorker.js
) を含む完全なコードは GitHub にあります。Versioning And Updating the Service Worker
If nothing were going to change on our website again, we could say we’re done.私たちは、Web サイトを二度と変更しないのなら、これで終わりと言えます。 しかし、サービス ワーカーはときどき更新する必要があります。 キャッシュ可能なパスをもっと追加したくなるかもしれません。 オフラインのフォールバックの方法を進化させたいかもしれない。 Google の Service Worker Precache のように、サービス ワーカーの管理をワークフローの一部にするための自動化されたツールがあることを強調したいと思います。 これを手作業でバージョン管理する必要はありません。 しかし、私のウェブサイトの複雑性は十分低いので、サービス ワーカーの変更を管理するために人間のバージョニング戦略を使用しています。 これは、
- バージョンを示すシンプルなバージョン文字列、
- 古いバージョンをクリーンアップする
activate
ハンドラの実装、 - 更新したサービス ワーカーの
activate
を高速化するinstall
ハンドラの更新、から構成されています。
Versioning Cache Keys
自分の
config
オブジェクトにversion
プロパティを追加できる:version: 'aether'
サービス ワーカーの更新版を配布するときはいつでもこれを変更しなければなりません。 ギリシャ神話の神々の名前を使用するのは、ランダムな文字列や数値よりも興味深いからです。
注: コードにいくつか変更を加え、接頭辞付きのキャッシュ キーを生成するための便利な関数 (
cacheName
) を追加しました。 余談ですが、完成したサービス ワーカーのコードで見ることができます。サービス ワーカーの名前を変更しない
あるとき、私はサービス ワーカーのファイル名の命名規則をあれこれと変えていました。 これを実行しないでください。 これを行うと、ブラウザは新しいサービス ワーカーを登録しますが、古いサービス ワーカーもインストールされたままになってしまいます。 これは面倒な状態です。
Don’t Use importScripts for config
私は、外部ファイルに
config
オブジェクトを置き、サービス ワーカー ファイルでself.importScripts()
を使用してそのスクリプトを取り込むという方法を取りました。 それは、サービス ワーカーの外部で私のconfig
を管理する妥当な方法のように思えましたが、問題がありました。ブラウザは、サービス ワーカー ファイルをバイト比較し、それらが更新されたかどうかを判断します (これは、いつダウンロードとインストールのサイクルを再トリガーするかを知る方法です)。 外部の
config
への変更はサービス ワーカー自体への変更を引き起こさないので、config
への変更がサービス ワーカーを更新する原因になっていないことを意味します。 Whoops.Adding An Activate Handler
バージョン固有のキャッシュ名を持つ目的は、以前のバージョンからのキャッシュをクリーンアップできるようにするためです。 アクティベート中に、現在のバージョン文字列が接頭辞として付いていないキャッシュが存在する場合、それらは残骸であるため削除されるべきであることがわかります。 これは現在、待機中のワーカーです。 デフォルトでは、更新されたサービスワーカーは、古いサービスワーカーをまだ使っているページが読み込まれている間は、起動しません。 しかし、
install
ハンドラを少し変更することで、これを高速化できます。self.addEventListener('install', event => { // … as before event.waitUntil( onInstall(event, config) .then( () => self.skipWaiting() ) );});
skipWaiting
はactivate
をすぐに発生させます。では、
activate
ハンドラを終了します。self.addEventListener('activate', event => { function onActivate (event, opts) { // … as above } event.waitUntil( onActivate(event, config) .then( () => self.clients.claim() ) );});
self.clients.claim
は、新しいサービス ワーカーを、そのスコープ内のすべてのオープン ページで直ちに有効にします。たーだーい!
バージョン管理されたサービス ワーカーができました。 バージョン管理された更新された
serviceWorker.js
ファイルは GitHub で見ることができます。Further Reading on SmashingMag:
- A Beginner’s Guide To Progressive Web Apps
- Building A Simple Cross-Browser Offline To-Do List
- World Wide Web, Not Wealthy Western Web
(JB, ML, AL, MSE)