Web バックグラウンド同期

コミュニティグループ報告書ドラフト,

このバージョン:
https://wicg.github.io/background-sync/spec/
課題追跡:
GitHub
編集者:
(Google)
(Google)

概要

この仕様は、Web アプリケーションがバックグラウンドでデータを同期できるようにする方法を記述する。

この文書のステータス

この仕様は、Web Platform Incubator Community Group によって公開された。 これは W3C 標準ではなく、W3C 標準化過程にもない。 W3C Community Contributor License Agreement (CLA) の下では、限定的なオプトアウトおよびその他の条件が 適用されることに注意。 W3C Community and Business Groups についてさらに学ぶ。

1. 導入

このセクションは非規範的である。

Web アプリケーションは、信頼性の低いネットワーク(例:携帯電話)や未知の 有効期間(ブラウザーが終了される、またはユーザーが移動する可能性がある)を持つ環境で実行されることが多い。 これにより、Web アプリからのクライアントデータ(写真のアップロード、文書の変更、作成済みメールなど)を サーバーと同期することが難しくなる。同期が完了する前にブラウザーが閉じられたりユーザーが移動したりした場合、 アプリはユーザーがページを再訪するまで再試行を待たなければならない。この仕様は、 最初に要求されたときの悪条件にもかかわらず同期の試行を継続できるように、 service worker の新しい onsync イベントを提供する。このイベントは バックグラウンドで 発火できる。この API は、 コンテンツの作成からサーバーとのコンテンツ同期までの時間を短縮することを意図している。

この API は service workers に依存しているため、この API によって提供される機能は 安全なコンテキストでのみ利用可能である。

ブラウジングコンテキストから background sync の機会を要求する:
function sendChatMessage(message) {
  return addChatMessageToOutbox(message).then(() => {
    // Wait for the scoped service worker registration to get a
    // service worker with an active state
    return navigator.serviceWorker.ready;
  }).then(reg => {
    return reg.sync.register('send-chats');
  }).then(() => {
    console.log('Sync registered!');
  }).catch(() => {
    console.log('Sync registration failed :(');
  });
}

上の例では、addChatMessageToOutbox は開発者定義の関数である。

service worker 内で sync イベントに反応する:

self.addEventListener('sync', event => {
  if (event.tag == 'send-chats') {
    event.waitUntil(
      getMessagesFromOutbox().then(messages => {
        // Post the messages to the server
        return fetch('/send', {
          method: 'POST',
          body: JSON.stringify(messages),
          headers: { 'Content-Type': 'application/json' }
        }).then(() => {
          // Success! Remove them from the outbox
          return removeMessagesFromOutbox(messages);
        });
      }).then(() => {
        // Tell pages of your success so they can update UI
        return clients.matchAll({ includeUncontrolled: true });
      }).then(clients => {
        clients.forEach(client => client.postMessage('outbox-processed'))
      })
    );
  }
});

上の例では、getMessagesFromOutboxremoveMessagesFromOutbox は 開発者定義の関数である。

2. 概念

sync イベントは、対応する service worker registration の origin について、 service worker clients のうち、その frame type が top-level または auxiliary であるものが存在しない場合、 バックグラウンドで実行されていると見なされる。

ユーザーエージェントは、ネットワーク接続を確立している場合、 online であると見なされる。ユーザーエージェントは、 online であることについて、より厳格な定義を使用してもよい。 そのようなより厳格な定義では、service worker または sync registration が関連付けられる origin を 考慮してもよい。

3. 構成要素

service worker registration は、要素型が sync registration である、関連付けられた sync registrations のリストを持つ。

sync registration は、tagstate から成るタプルである。

sync registration は、関連付けられた DOMString である tag を持つ。

sync registration は、関連付けられた registration state を持つ。これは pending, waiting, firing, または reregisteredWhileFiring のいずれかである。 これは初期状態で pending に設定される。

sync registration は、関連付けられた service worker registration を持つ。これは初期状態で null に設定される。

1 つの sync registrations のリスト内では、各 sync registration は一意の tag を持たなければならない。

4. Permissions との統合

Web Background Synchronization API は、既定の強力な機能であり、name "background-sync" によって識別される。

5. プライバシー上の考慮事項

5.1. 許可

ユーザーエージェントは、ユーザーが background sync を無効にする手段を提供してもよい。

注: Background sync は既定で有効にされるべきである。 許可が拒否されていることは例外的な場合と見なされる。

5.2. 位置トラッキング

バックグラウンドで の間に onsync イベント内で行われる fetch 要求は、 ユーザーがページを離れた後にクライアントの IP アドレスをサーバーに明らかにする可能性がある。 ユーザーエージェントは、再試行回数および sync イベントの継続時間に上限を設けることで トラッキングを制限するべきである。

5.3. 履歴漏えい

バックグラウンドで の間に onsync イベント内で行われる fetch 要求は、 受動的な盗聴者にクライアントのナビゲーション履歴に関する何かを明らかにする可能性がある。 たとえば、クライアントがサイト https://example.com を訪問し、それが sync イベントを登録するが、 ユーザーがページから移動しネットワークを変更するまで発火しない場合がある。新しいネットワーク上の受動的な盗聴者は、 onsync イベントが行う fetch 要求を見る可能性がある。fetch 要求は HTTPS であるため要求内容は 漏えいしないが、ドメインは(DNS ルックアップおよび要求先の IP アドレスを介して)漏えいする可能性がある。

6. API の説明

6.1. ServiceWorkerRegistration インターフェイスへの拡張

ServiceWorkerRegistration/sync

現在のエンジン 1 つだけで利用可能。

FirefoxなしSafariなしChrome49+
Opera36+Edge79+
Edge (Legacy)なしIEなし
Firefox for AndroidなしiOS SafariなしChrome for Android49+Android WebView49+Samsung Internet4.0+Opera Mobile36+
partial interface ServiceWorkerRegistration {
  readonly attribute SyncManager sync;
};

sync 属性は、SyncManager を公開する。 これは、その属性が公開されている ServiceWorkerRegistration によって表される、関連付けられた service worker registration を持つ。

6.2. SyncManager インターフェイス

SyncManager

現在のエンジン 1 つだけで利用可能。

FirefoxなしSafariなしChrome49+
OperaなしEdge79+
Edge (Legacy)なしIEなし
Firefox for AndroidなしiOS SafariなしChrome for Android49+Android WebView49+Samsung Internet5.0+Opera Mobileなし
[Exposed=(Window,Worker)]
interface SyncManager {
  Promise<undefined> register(DOMString tag);
  Promise<sequence<DOMString>> getTags();
};

SyncManager/register

現在のエンジン 1 つだけで利用可能。

FirefoxなしSafariなしChrome49+
OperaなしEdge79+
Edge (Legacy)なしIEなし
Firefox for AndroidなしiOS SafariなしChrome for Android49+Android WebView49+Samsung Internet5.0+Opera Mobileなし

register(tag) メソッドは、呼び出されたとき、 新しい promise promise を返し、次の手順を 並列で実行しなければならない:

  1. serviceWorkerRegistration を、SyncManager の 関連付けられた service worker registration とする。
  2. serviceWorkerRegistrationactive worker が null の場合、promiseInvalidStateErrorreject し、これらの手順を中止する。
  3. ユーザーが background sync を無効にしている場合、promiseNotAllowedErrorreject し、これらの手順を中止する。
  4. isBackground を true とする。
  5. serviceWorkerRegistration の origin に対する service worker clients 内の client それぞれについて:
    1. clientframe type が top-level または auxiliary である場合、isBackground を false に設定する。
  6. isBackground が true の場合、promiseInvalidAccessErrorreject し、これらの手順を中止する。
  7. currentRegistration を、存在する場合は serviceWorkerRegistrationsync registrations のリスト内の、 tagtag に等しい registration とし、そうでなければ null とする。
  8. currentRegistration が null でない場合:
    1. currentRegistrationregistration statewaiting である場合、 currentRegistrationregistration statepending に設定する。
    2. currentRegistrationregistration statefiring である場合、 currentRegistrationregistration statereregisteredWhileFiring に設定する。
    3. promiseResolve する。
    4. ユーザーエージェントが現在 online であり、かつ currentRegistrationregistration statepending である場合、 currentRegistration に対して sync event を発火する
  9. そうでない場合:
    1. newRegistration を新しい sync registration とする。
    2. newRegistration の関連付けられた tagtag に設定する。
    3. newRegistration の関連付けられた service worker registrationserviceWorkerRegistration に設定する。
    4. newRegistrationserviceWorkerRegistrationsync registrations のリストに追加する。
    5. promiseResolve する。
    6. ユーザーエージェントが現在 online である場合、 newRegistration に対して sync event を発火する

SyncManager/getTags

現在のエンジン 1 つだけで利用可能。

FirefoxなしSafariなしChrome49+
OperaなしEdge79+
Edge (Legacy)なしIEなし
Firefox for AndroidなしiOS SafariなしChrome for Android49+Android WebView49+Samsung Internet5.0+Opera Mobileなし

getTags() メソッドは、呼び出されたとき、新しい promise promise を返し、次の手順を 並列で実行しなければならない:

  1. serviceWorkerRegistration を、SyncManager の 関連付けられた service worker registration とする。
  2. currentTags を新しい sequence とする。
  3. serviceWorkerRegistrationsync registrations のリスト内の registration それぞれについて、registration の関連付けられた tagcurrentTags に追加する。
  4. promisecurrentTagsResolve する。

6.3. sync イベント

SyncEvent

現在のエンジン 1 つだけで利用可能。

FirefoxなしSafariなしChrome49+
Opera?Edge79+
Edge (Legacy)なしIEなし
Firefox for AndroidなしiOS SafariなしChrome for Android49+Android WebViewなしSamsung Internet5.0+Opera Mobile?

ServiceWorkerGlobalScope/onsync

すべての現在のエンジンで利用可能。

Firefox44+Safari11.1+Chrome49+
Opera24+Edge79+
Edge (Legacy)なしIEなし
Firefox for Android44+iOS Safari11.3+Chrome for Android49+Android WebView49+Samsung Internet5.0+Opera Mobile24+

SyncEvent/SyncEvent

現在のエンジン 1 つだけで利用可能。

FirefoxなしSafariなしChrome49+
Opera?Edge79+
Edge (Legacy)なしIEなし
Firefox for AndroidなしiOS SafariなしChrome for Android49+Android WebViewなしSamsung Internet5.0+Opera Mobile?
partial interface ServiceWorkerGlobalScope {
  attribute EventHandler onsync;
};

[Exposed=ServiceWorker]
interface SyncEvent : ExtendableEvent {
  constructor(DOMString type, SyncEventInit init);
  readonly attribute DOMString tag;
  readonly attribute boolean lastChance;
};

dictionary SyncEventInit : ExtendableEventInit {
  required DOMString tag;
  boolean lastChance = false;
};

注: SyncEvent インターフェイスは、発火中の sync registration を表す。イベントを登録したページ(または worker)が 実行中である場合、ユーザーエージェントはネットワーク接続が利用可能になり次第 sync イベントを発火する。 そうでない場合、ユーザーエージェントは都合がつき次第イベントを実行するべきである。sync イベントが失敗した場合、 ユーザーエージェントは任意の時点で再試行することを決定してもよい。lastChance 属性は、ユーザーエージェントが現在の試行後にこの sync のさらなる試行を行わない場合に true である。

lastChance に反応する:
self.addEventListener('sync', event => {
  if (event.tag == 'important-thing') {
    event.waitUntil(
      doImportantThing().catch(err => {
        if (event.lastChance) {
          self.registration.showNotification("Important thing failed");
        }
        throw err;
      })
    );
  }
});

上の例は、ユーザーに notification を表示することで、 lastChance に反応する。これには、その origin が notifications を表示する許可を 持つ必要がある。

上の例では、doImportantThing は開発者定義の関数である。

ユーザーエージェントが online に変わるたびに、ユーザーエージェントは sync event を発火するべきである。 これは、sync registration のうち、その registration statepending であるものそれぞれについて行う。 イベントは任意の順序で発火されてもよい。

sync registration registration に対して sync event を発火するには、ユーザーエージェントは次の手順を実行しなければならない:

  1. Assert: registrationregistration statepending である。
  2. serviceWorkerRegistration を、registration に関連付けられた service worker registration とする。
  3. Assert: registrationserviceWorkerRegistration に関連付けられた sync registrations のリスト内に存在する。
  4. registrationregistration statefiring に設定する。
  5. serviceWorkerRegistration 上で、次のプロパティを持つ SyncEvent を使用して、"sync" Fire Functional Event する:

    SyncEvent/tag

    現在のエンジン 1 つだけで利用可能。

    FirefoxなしSafariなしChrome49+
    Opera?Edge79+
    Edge (Legacy)なしIEなし
    Firefox for AndroidなしiOS SafariなしChrome for Android49+Android WebViewなしSamsung Internet5.0+Opera Mobile?
    tag
    registration に関連付けられた tag

    SyncEvent/lastChance

    現在のエンジン 1 つだけで利用可能。

    FirefoxなしSafariなしChrome49+
    Opera?Edge79+
    Edge (Legacy)なしIEなし
    Firefox for AndroidなしiOS SafariなしChrome for Android49+Android WebViewなしSamsung Internet5.0+Opera Mobile?
    lastChance
    この sync event が失敗した場合にユーザーエージェントが 再試行するなら false、現在の試行後に さらなる試行が行われないなら true。

    その後、dispatchedEvent で次の手順を実行する:

    1. waitUntilPromise を、dispatchedEventextended lifetime promisesすべてを待機する結果とする。
    2. waitUntilPromise充足時に、次の手順をアトミックに実行する:
      1. registration の state が reregisteredWhileFiring である場合:
        1. registration の state を pending に設定する。
        2. ユーザーエージェントが現在 online である場合、registration に対して sync event を発火する
        3. これらの手順の残りを中止する。
      2. Assert: registrationregistration statefiring である。
      3. registrationserviceWorkerRegistrationsync registration のリストから削除する。
    3. waitUntilPromise拒否時、または service worker終了によってスクリプトが中止された場合、 次の手順をアトミックに実行する:
      1. registration の state が reregisteredWhileFiring である場合:
        1. registration の state を pending に設定する。
        2. ユーザーエージェントが現在 online である場合、registration に対して sync event を発火する
        3. これらの手順の残りを中止する。
      2. dispatchedEventlastChance 属性が false の場合、registrationregistration statewaiting に設定し、 次の手順を 並列で実行する:
        1. ユーザーエージェント定義の時間だけ待つ。
        2. registrationregistration statewaiting でない場合、これらの下位手順を中止する。
        3. registrationregistration statepending に設定する。
        4. ユーザーエージェントが現在 online である場合、registration に対して sync event を発火する
      3. そうでない場合、registrationserviceWorkerRegistrationsync registrations のリストから削除する。

ユーザーエージェントは、SyncEvent の lifetime extension および実行時間に対して、一般の ExtendableEvent に 課される時間制限よりも厳しい時間制限を課してもよい。特に、 lastChance が true であるイベントは、大幅に短縮された時間制限を持ってもよい。

ユーザーエージェントは、何らかのユーザーエージェント定義のヒューリスティックに基づき、 sync event再試行する

適合性

適合性要件は、記述的な表明と RFC 2119 用語の組み合わせによって表現される。 この文書の規範的部分における キーワード “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, および “OPTIONAL” は、RFC 2119 に記述されているとおりに解釈される。 ただし、読みやすさのため、 これらの語はこの仕様ではすべて大文字で現れるとは限らない。

この仕様のすべてのテキストは規範的である。 ただし、非規範的であると明示的に印が付けられたセクション、例、および注記は除く。 [RFC2119]

この仕様の例は、“for example” という語で導入されるか、 次のように class="example" を用いて規範的テキストから分離される:

これは参考情報としての例の一例である。

参考情報としての注記は “Note” という語で始まり、 次のように class="note" を用いて規範的テキストから分離される:

注、これは参考情報としての注記である。

索引

この 仕様で定義される用語

参照により定義される 用語

参考文献

規範的参考文献

[ECMASCRIPT]
ECMAScript Language Specification. URL: https://tc39.es/ecma262/multipage/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[PERMISSIONS]
Marcos Caceres; Mike Taylor; Jeffrey Yasskin. Permissions. 23 October 2021. WD. URL: https://www.w3.org/TR/permissions/
[PROMISES-GUIDE]
Writing Promise-Using Specifications. 24 July 2015. W3C TAG の Finding. URL: https://www.w3.org/2001/tag/doc/promises-guide
[RFC2119]
S. Bradner. RFC において要求レベルを示すために用いる キーワード. March 1997. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119
[SECURE-CONTEXTS]
Mike West. Secure Contexts. 18 September 2021. CR. URL: https://www.w3.org/TR/secure-contexts/
[SERVICE-WORKERS-1]
Alex Russell; et al. Service Workers 1. 19 November 2019. CR. URL: https://www.w3.org/TR/service-workers-1/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. Living Standard. URL: https://webidl.spec.whatwg.org/

IDL 索引

partial interface ServiceWorkerRegistration {
  readonly attribute SyncManager sync;
};

[Exposed=(Window,Worker)]
interface SyncManager {
  Promise<undefined> register(DOMString tag);
  Promise<sequence<DOMString>> getTags();
};

partial interface ServiceWorkerGlobalScope {
  attribute EventHandler onsync;
};

[Exposed=ServiceWorker]
interface SyncEvent : ExtendableEvent {
  constructor(DOMString type, SyncEventInit init);
  readonly attribute DOMString tag;
  readonly attribute boolean lastChance;
};

dictionary SyncEventInit : ExtendableEventInit {
  required DOMString tag;
  boolean lastChance = false;
};