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

Jake Archibald 氏
Jake Archibald

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

問題

インターネットは時間を無駄にするのに最適です。インターネットで時間を無駄にすることなく、猫は花が嫌いカメレオンは泡が好きであること、私たち自身の Eric Bidelman90 年代後半のパットパット ゴルフのヒーローであることなどを知ることができません。

しかし、場合によっては、時間を無駄にしたくないこともあります。望ましいユーザー エクスペリエンスは次のようになります。

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

残念ながら、このような状況は不安定な接続によって中断されることがよくあります。あらゆる人が経験したことがあるでしょう。あなたは白い画面またはスピナーを見ています。あきらめて自分の人生を守るべきだとわかっていても、念のためさらに 10 秒待ちます。その 10 秒後、特になし。

でも、今すぐあきらめるのはなぜでしょうか。すでに時間を割いているのに、何も持たずに立ち去っても無駄ですから、待たされ続けることになります。この時点で、あきらめたいことはありますが、待ったならすべて読み込まれるよりも前に、その 2 番目であることはわかっています。

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

現時点では、ユーザーがメッセージで [送信] をクリックすると、返信が完了するまでスピナーを注視する必要があります。ユーザーが別のページに移動したりタブを閉じようとした場合は、onbeforeunload を使用して「いいえ、このスピナーをもう少し見ておいていただけますか。すみません」ユーザーが接続していない場合は、「しばらくしてからもう一度お試しください」と表示されます。

これはおかしい。バックグラウンド同期でもっと便利に。

ソリューション

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

接続がないときにメッセージを送信しようとすると、幸いなことに、接続されたときにバックグラウンドでメッセージを送信します。

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

  1. 絵文字を開きます
  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 を返します。これが実現されると、同期は完了します。失敗した場合は、別の同期が再試行されるようにスケジュールされます。同期の再試行も接続を待機し、指数バックオフを使用します。

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

こちらのデモでは、同期イベントを使用して通知を表示する必要が最小限に抑えられています。

バックグラウンド同期はどのような用途に使用できますか?

理想的には、このページの有効期間を超えて重要なデータ送信をスケジュールするために使用できます。チャット メッセージ、メール、ドキュメントの更新、設定変更、写真のアップロードなど、ユーザーが移動したりタブを閉じたりしてもサーバーにアクセスしたいもの。ページではこれらの情報を indexDB の「送信ボックス」ストアに保存し、Service Worker がそれらを取得して送信します。

ただし、小規模なデータを取得するためにも使用できます。

もう 1 つデモを行います。

これは、ページ読み込みの強化用に作成したオフライン wikipedia デモです。それにバックグラウンド同期の魔法をかけたんだ。

実際に試してみましょう。Chrome 49 以降を使用していることを確認します。

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

このパターンを使用すると、ユーザーはスマートフォンをポケットに入れて、必要な情報を取得したときにスマートフォンがアラートしてくれるため、毎日の生活に取り組めます。

権限

お見せしたデモではウェブ通知を使用します。ウェブ通知には権限が必要ですが、バックグラウンド同期自体は使用しません。

同期イベントはユーザーがサイトのページを開いている間に完了することが多いため、ユーザーに許可を求めるのは使い勝手が良くありません。その代わりに、不正使用を防ぐために、同期を登録してトリガーできるタイミングを制限しています。例:

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

もちろん、実際の使用状況に基づいて、これらの制限を緩和または強化することもできます。

段階的な機能向上

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 の Stable 版へのバックグラウンド同期を予定しており、これに伴い「定期的なバックグラウンド同期」の開発を進めています。定期的なバックグラウンド同期により、時間間隔、バッテリーの状態、ネットワークの状態によって制限されるイベントをリクエストできます。これには当然のことながら、ユーザーの許可が必要です。また、こうしたイベントが発生するタイミングや頻度はブラウザによります。つまり、ニュース サイトは 1 時間ごとに同期をリクエストしても、ブラウザはそのサイトを 07:00 にしか読んでいないと認識するため、同期は毎日 06:50 に行われます。このアイデアは 1 回限りの同期よりも少し先にありますが、実現しようとしています。

Android と iOS で成功したパターンをウェブに少しずつ導入しつつ、ウェブの良さも変わらないようにしています。