バックグラウンド同期の導入

バックグラウンド同期は、ユーザーが安定した接続を確立するまでアクションを延期できる新しい web API です。これにより、ユーザーが送信したいものが確実に送信されます。

問題

インターネットは時間を浪費するのに最適な場所です。インターネットで時間を浪費しなければ、猫は花が嫌いだとか、カメレオンはシャボン玉が大好きだとか、Google の Eric Bidelman90 年代後半のパットゴルフのヒーローだとか、知ることはできません。

でも、時には時間を無駄にしないことも必要です。望ましいユーザー エクスペリエンスは次のようになります。

  1. スマートフォンをポケットから取り出す。
  2. 小さな目標を達成する。
  3. スマートフォンをポケットに戻します。
  4. 生活を再開する。

残念ながら、接続状態が悪いと、このエクスペリエンスが中断されることがあります。誰にでもあることです。白い画面やスピナーを見つめながら、もうあきらめて他の作業をすべきだとわかっているのに、念のためもう 10 秒待ってみる。10 秒後はどうなりますか?特になし。

でも、ここであきらめるのはもったいない。すでに時間をかけているため、何も得られないまま放棄するのはもったいないと思い、待機を続けます。この時点では、あきらめたい気持ちになりますが、あきらめた瞬間に、もう少し待っていればすべて読み込まれていたはずだと後悔することになります。

サービス ワーカーは、キャッシュからコンテンツを配信することで、ページの読み込み部分を解決します。では、ページからサーバーに何かを送信する必要がある場合はどうすればよいでしょうか。

現在のところ、ユーザーがメッセージを送信すると、完了するまでスピナーを見つめ続ける必要があります。タブから移動したり、タブを閉じたりしようとすると、onbeforeunload を使用して、「このスピナーをもう少し見つめてください。申し訳ございません」お客様が接続していない場合は、「申し訳ございませんが、後でもう一度お試しください」と伝えます。

これはばかげている。バックグラウンド同期を使用すると、より多くのことができます。

ソリューション

次の動画は、絵文字のみのチャット デモである Emojoy を示しています。これはプログレッシブ ウェブアプリで、オフライン ファーストで動作します。アプリはプッシュ メッセージと通知を使用し、バックグラウンド同期を使用します。

ユーザーが接続していないときにメッセージを送信しようとすると、接続が確立されると、そのメッセージはバックグラウンドで送信されます。

2016 年 3 月現在、バックグラウンド同期は Chrome バージョン 49 以降で利用できます。動作を確認する手順は次のとおりです。

  1. Emojoy を開きます
  2. オフラインにする(機内モードを使用するか、近くのファラデーケージに移動する)。
  3. メッセージを入力します。
  4. ホーム画面に戻ります(必要に応じてタブまたはブラウザを閉じます)。
  5. オンラインに接続します。
  6. メッセージがバックグラウンドで送信されます。

このようにバックグラウンドで送信できると、パフォーマンスが向上したように感じられます。アプリはメッセージの送信についてそれほど気にする必要がないため、メッセージをすぐに出力に追加できます。

バックグラウンド同期をリクエストする方法

真の拡張可能なウェブ スタイルで、必要なことを自由に行うことができる低レベルの機能です。ユーザーが接続したときにイベントを発生させるようにリクエストします。ユーザーがすでに接続している場合は、すぐに発生します。その後、そのイベントをリッスンして必要な処理を行います。

プッシュ メッセージングと同様に、イベント ターゲットとして Service Worker を使用するため、ページが開いていないときにも機能します。同期を開始するには、ページから登録します。

// Register your service worker:
navigator.serviceWorker.register('/sw.js');

// Then later, request a one-off sync:
navigator.serviceWorker.ready.then(function(swRegistration) {
  return swRegistration.sync.register('myFirstSync');
});
 ```

Then listen for the event in `/sw.js`:

```js
self.addEventListener('sync', function(event) {
  if (event.tag == 'myFirstSync') {
    event.waitUntil(doSomeStuff());
  }
});

これで完了です。上記の例では、doSomeStuff() は、実行しようとしている処理の成功/失敗を示す Promise を返す必要があります。Promise が満たされると、同期が完了します。失敗した場合は、別の同期が再試行されるようにスケジュールされます。再試行の同期も接続を待機し、指数バックオフを使用します。

同期のタグ名(上記の例では「myFirstSync」)は、特定の同期で一意である必要があります。保留中の同期と同じタグを使用して同期を登録すると、既存の同期と統合されます。つまり、ユーザーがメッセージを送信するたびに「受信トレイの消去」の同期を登録できますが、オフライン中に 5 通のメッセージを送信した場合、オンラインになったときに 1 回だけ同期されます。5 つの個別の同期イベントが必要な場合は、一意のタグを使用します。

最小限の処理を行うシンプルなデモは、同期イベントを使用して通知を表示します。

バックグラウンド同期は何に使用できますか?

理想的には、ページの存続期間を超えて重要なデータの送信をスケジュール設定します。チャット メッセージ、メール、ドキュメントの更新、設定の変更、写真のアップロードなど、ユーザーが他のページに移動したりタブを閉じたりしてもサーバーに送信されるようにしたいすべてのもの。ページは、indexedDB の「送信トレイ」ストアにこれらのデータを保存し、Service Worker がデータを取得して送信します。

ただし、少量のデータの取得にも使用できます。

別のデモ

これは、ページ読み込みの高速化のために作成したオフライン ウィキペディアのデモです。その後、バックグラウンド同期の機能を追加しました。

ぜひお試しください。Chrome 49 以降を使用していることを確認し、次の操作を行います。

  1. 任意の記事(Chrome など)に移動します。
  2. オフラインにする(機内モードを使用するか、私のようにひどいモバイル プロバイダに加入する)。
  3. 別の記事へのリンクをクリックします。
  4. ページの読み込みに失敗したことが通知されます(ページの読み込みに時間がかかる場合も、このメッセージが表示されます)。
  5. 通知に同意します。
  6. ブラウザを閉じます。
  7. オンライン
  8. 記事がダウンロードされ、キャッシュに保存されて表示可能になると通知が届きます。

このパターンを使用すると、ユーザーはスマートフォンをポケットに入れて日常生活を送ることができます。必要な情報が取得されるとスマートフォンから通知が届きます。

権限

私が示したデモではウェブ通知を使用していますが、これは権限を必要としますが、バックグラウンド同期自体は必要としません。

同期イベントは、ユーザーがサイトのページを開いている間に完了することが多く、ユーザーの許可を要求するとユーザー エクスペリエンスが低下します。代わりに、不正使用を防ぐため、同期を登録してトリガーできるタイミングを制限しています。次に例を示します。

  • 同期イベントを登録できるのは、ユーザーがサイトのウィンドウを開いている場合のみです。
  • イベントの実行時間には上限があるため、イベントを使用してサーバーへの ping を x 秒ごとに実行したり、ビットコインをマイニングしたりすることはできません。

もちろん、これらの制限は、実際の使用状況に応じて緩和または強化される場合があります。

プログレッシブ エンハンスメント

すべてのブラウザでバックグラウンド同期がサポートされるまでには、特に Safari と Edge が Service Worker をまだサポートしていないため、しばらく時間がかかります。ただし、プログレッシブ エンハンスメントは次の点で役立ちます。

if ('serviceWorker' in navigator && 'SyncManager' in window) {
  navigator.serviceWorker.ready.then(function(reg) {
    return reg.sync.register('tag-name');
  }).catch(function() {
    // system was unable to register for a sync,
    // this could be an OS-level restriction
    postDataFromThePage();
  });
} else {
  // serviceworker/sync not supported
  postDataFromThePage();
}

Service Worker やバックグラウンド同期を使用できない場合は、これまでどおりページからコンテンツを投稿します。

ユーザーの接続状況が良好に見える場合でも、バックグラウンド同期を使用することをおすすめします。データ送信中にナビゲーションやタブが閉じられるのを防ぐことができます。

今後について

バックグラウンド同期は、2016 年前半に Chrome の安定版にリリースされる予定です。また、そのバリエーションである「定期的なバックグラウンド同期」も開発中です。定期的なバックグラウンド同期では、時間間隔、バッテリーの状態、ネットワークの状態によって制限されたイベントをリクエストできます。もちろん、ユーザーの許可が必要になります。また、これらのイベントの発生タイミングと頻度はブラウザによって異なります。つまり、ニュースサイトが 1 時間ごとに同期をリクエストしても、ブラウザがそのサイトを 7 時ちょうどにしか閲覧していないと判断すると、同期は毎日 6 時 50 分に実行されます。この機能は、1 回限りの同期よりも少し先ですが、今後実装される予定です。

Google は、ウェブの優れた点はそのままに、Android や iOS で成功しているパターンをウェブにも少しずつ取り入れています。