1. 소개
이 절은 비규범적이다.
Web Applications는 신뢰할 수 없는 네트워크(예: 휴대전화)와 알 수 없는 수명(브라우저가 종료되거나 사용자가 다른 곳으로 이동할 수 있음)을 가진 환경에서 실행되는 경우가 많다. 이로 인해 웹 앱의 클라이언트 데이터(예: 사진 업로드, 문서 변경 또는 작성된 이메일)를 서버와 동기화하기가 어렵다. 브라우저가 닫히거나 사용자가 동기화를 완료하기 전에 다른 곳으로 이동하면, 앱은 사용자가 페이지를 다시 방문할 때까지 기다렸다가 다시 시도해야 한다. 이 명세는 처음 요청된 시점의 불리한 조건에도 불구하고 동기화 시도를 계속할 수 있도록 service worker에서 백그라운드에서 발생할 수 있는 새로운 onsync 이벤트를 제공한다. 이 API는 콘텐츠 생성과 서버와의 콘텐츠 동기화 사이의 시간을 줄이기 위한 것이다.
이 API는 service workers에 의존하므로, 이 API가 제공하는 기능은 secure context에서만 사용할 수 있다.
function sendChatMessage( message) { return addChatMessageToOutbox( message). then(() => { // scoped service worker registration이 active 상태의 // service worker를 얻을 때까지 기다린다 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=> { // 메시지를 서버로 게시한다 return fetch( '/send' , { method: 'POST' , body: JSON. stringify( messages), headers: { 'Content-Type' : 'application/json' } }). then(() => { // 성공! outbox에서 제거한다 return removeMessagesFromOutbox( messages); }); }). then(() => { // 성공 사실을 페이지에 알려 UI를 갱신할 수 있게 한다 return clients. matchAll({ includeUncontrolled: true }); }). then( clients=> { clients. forEach( client=> client. postMessage( 'outbox-processed' )) }) ); } });
위 예제에서 getMessagesFromOutbox와 removeMessagesFromOutbox는
개발자가 정의한 함수이다.
2. 개념
해당 service worker registration의 origin에 대해 frame type이 top-level 또는 auxiliary인 service worker clients가 존재하지 않는 경우, sync 이벤트는 백그라운드에서 실행되는 것으로 간주된다.
사용자 에이전트가 네트워크 연결을 설정한 경우 사용자 에이전트는 online인 것으로 간주된다. 사용자 에이전트는 online에 대해 더 엄격한 정의를 사용할 수 있다(MAY). 이러한 더 엄격한 정의는 service worker 또는 sync registration이 연결된 특정 origin을 고려할 수 있다(MAY).
3. 구성 요소
service worker registration은 element type이 sync registration인 연관된 sync registrations 목록을 가진다.sync registration은 tag와 state로 구성된 tuple이다.
sync registration은 DOMString인 연관된 tag를 가진다.
sync registration은 연관된 registration state를 가지며, 이는 pending, waiting, firing, 또는 reregisteredWhileFiring 중 하나이다. 이는 처음에 pending으로 설정된다.
sync registration은 연관된 service worker registration을 가진다. 이는 처음에 null로 설정된다.
하나의 sync registrations 목록 안에서 각 sync registration은 고유한 tag를 가져야 한다(MUST).
4. Permissions 통합
Web Background Synchronization API는 default powerful feature이며, name "background-sync"로 식별된다.5. 개인정보 고려 사항
5.1. 권한
사용자 에이전트는 사용자가 background sync를 비활성화할 수 있는 방법을 제공할 수 있다(MAY).참고: Background sync는 기본적으로 활성화되어야 한다(SHOULD). 권한이 거부되는 것은 예외적인 경우로 간주된다.
5.2. 위치 추적
백그라운드에서 실행되는 동안 onsync 이벤트 내의 fetch requests는 사용자가 페이지를 떠난 뒤에 클라이언트의 IP 주소를 서버에 노출할 수 있다. 사용자 에이전트는 재시도 횟수와 sync 이벤트의 지속 시간을 제한하여 추적을 제한해야 한다(SHOULD).5.3. 방문 기록 누출
백그라운드에서 실행되는 동안 onsync 이벤트 내의 fetch requests는 수동적 도청자에게 클라이언트의 navigation history에 관한 무언가를 드러낼 수 있다. 예를 들어, 클라이언트가 https://example.com 사이트를 방문하고, 이 사이트가 sync 이벤트를 등록하지만, 사용자가 페이지를 벗어나 네트워크를 변경한 뒤에야 이벤트가 발생할 수 있다. 새 네트워크의 수동적 도청자는 onsync 이벤트가 만드는 fetch requests를 볼 수 있다. fetch requests는 HTTPS이므로 요청 내용은 누출되지 않지만 domain은 (DNS 조회와 요청의 IP 주소를 통해) 노출될 수 있다.6. API 설명
6.1. ServiceWorkerRegistration
인터페이스에 대한 확장
ServiceWorkerRegistration/sync
현재 엔진 하나에만 있음.
Opera36+Edge79+
Edge (Legacy)없음IE없음
Android용 Firefox없음iOS Safari없음Android용 Chrome49+Android WebView49+Samsung Internet4.0+Opera Mobile36+
partial interface ServiceWorkerRegistration {readonly attribute SyncManager ; };sync
속성은 syncSyncManager를
노출하며,
이는 해당 속성이 노출되는 ServiceWorkerRegistration로
표현되는 연관된 service worker registration을 가진다.
6.2.
SyncManager
인터페이스
현재 엔진 하나에만 있음.
Opera없음Edge79+
Edge (Legacy)없음IE없음
Android용 Firefox없음iOS Safari없음Android용 Chrome49+Android WebView49+Samsung Internet5.0+Opera Mobile없음
[Exposed =(Window ,Worker )]interface {SyncManager Promise <undefined >register (DOMString );tag Promise <sequence <DOMString >>getTags (); };
현재 엔진 하나에만 있음.
Opera없음Edge79+
Edge (Legacy)없음IE없음
Android용 Firefox없음iOS Safari없음Android용 Chrome49+Android WebView49+Samsung Internet5.0+Opera Mobile없음
메서드는 호출되면 새
promise promise를 반환하고 다음 단계를 병렬로 실행해야 한다(MUST):
register(tag)
- serviceWorkerRegistration을
SyncManager의 연관된 service worker registration으로 둔다. - serviceWorkerRegistration의 active worker가 null이면,
promise를
InvalidStateError로 reject하고 이 단계들을 abort한다. - 사용자가 background sync를 비활성화했으면,
promise를
NotAllowedError로 reject하고 이 단계들을 abort한다. - isBackground를 true로 둔다.
-
serviceWorkerRegistration의 origin에 대한
service worker clients의 각
client에 대해:
- client의 frame type이 top-level 또는 auxiliary이면, isBackground를 false로 설정한다.
- isBackground가 true이면, promise를
InvalidAccessError로 reject하고 이 단계들을 abort한다. - currentRegistration을, 존재한다면 serviceWorkerRegistration의 sync registrations 목록에서 tag가 tag와 같은 registration으로 두고, 그렇지 않으면 null로 둔다.
-
currentRegistration이 null이 아니면:
- currentRegistration의 registration state가 waiting이면, currentRegistration의 registration state를 pending으로 설정한다.
- currentRegistration의 registration state가 firing이면, currentRegistration의 registration state를 reregisteredWhileFiring으로 설정한다.
- promise를 Resolve한다.
- 사용자 에이전트가 현재 online이고 currentRegistration의 registration state가 pending이면, currentRegistration에 대해 sync 이벤트를 발생시킨다.
-
그렇지 않으면:
- newRegistration을 새 sync registration으로 둔다.
- newRegistration의 연관된 tag를 tag로 설정한다.
- newRegistration의 연관된 service worker registration을 serviceWorkerRegistration로 설정한다.
- newRegistration을 serviceWorkerRegistration의 sync registrations 목록에 추가한다.
- promise를 Resolve한다.
- 사용자 에이전트가 현재 online이면, newRegistration에 대해 sync 이벤트를 발생시킨다.
현재 엔진 하나에만 있음.
Opera없음Edge79+
Edge (Legacy)없음IE없음
Android용 Firefox없음iOS Safari없음Android용 Chrome49+Android WebView49+Samsung Internet5.0+Opera Mobile없음
메서드는 호출되면 새 promise promise를 반환하고 다음 단계를
병렬로 실행해야 한다(MUST):
getTags()
- serviceWorkerRegistration을
SyncManager의 연관된 service worker registration으로 둔다. - currentTags를 새
sequence로 둔다. - serviceWorkerRegistration의 sync registrations 목록의 각 registration에 대해, registration의 연관된 tag를 currentTags에 추가한다.
- promise를 currentTags로 Resolve한다.
6.3. sync 이벤트
현재 엔진 하나에만 있음.
Opera?Edge79+
Edge (Legacy)없음IE없음
Android용 Firefox없음iOS Safari없음Android용 Chrome49+Android WebView없음Samsung Internet5.0+Opera Mobile?
ServiceWorkerGlobalScope/onsync
모든 현재 엔진에 있음.
Opera24+Edge79+
Edge (Legacy)없음IE없음
Android용 Firefox44+iOS Safari11.3+Android용 Chrome49+Android WebView49+Samsung Internet5.0+Opera Mobile24+
현재 엔진 하나에만 있음.
Opera?Edge79+
Edge (Legacy)없음IE없음
Android용 Firefox없음iOS Safari없음Android용 Chrome49+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
인터페이스는 firing sync registration을 나타낸다. 이벤트를 등록한 page(또는 worker)가
실행 중이면, 사용자 에이전트는 network connectivity가 사용 가능해지는 즉시 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으로 변경될 때마다, 사용자 에이전트는 registration state가 pending인 각 sync registration에 대해 sync 이벤트를 발생시켜야 한다(SHOULD). 이벤트들은 어떤 순서로든 발생할 수 있다.
sync registration registration에 대해 sync 이벤트를 발생시키려면, 사용자 에이전트는 다음 단계를 실행해야 한다(MUST):
- Assert: registration의 registration state는 pending이다.
- serviceWorkerRegistration을 registration과 연관된 service worker registration으로 둔다.
- Assert: registration은 serviceWorkerRegistration과 연관된 sync registrations 목록에 존재한다.
- registration의 registration state를 firing으로 설정한다.
-
serviceWorkerRegistration에서 다음 속성을 사용하여
SyncEvent로 "sync" Fire Functional Event한다:-
현재 엔진 하나에만 있음.
Firefox없음Safari없음Chrome49+
Opera?Edge79+
Edge (Legacy)없음IE없음
Android용 Firefox없음iOS Safari없음Android용 Chrome49+Android WebView없음Samsung Internet5.0+Opera Mobile?tag - registration과 연관된 tag
-
현재 엔진 하나에만 있음.
Firefox없음Safari없음Chrome49+
Opera?Edge79+
Edge (Legacy)없음IE없음
Android용 Firefox없음iOS Safari없음Android용 Chrome49+Android WebView없음Samsung Internet5.0+Opera Mobile?lastChance - 사용자 에이전트가 이 sync 이벤트가 실패하면 재시도할 경우 false, 또는 현재 시도 이후 더 이상의 시도가 이루어지지 않을 경우 true.
그런 다음 dispatchedEvent로 다음 단계를 실행한다:
- waitUntilPromise를 dispatchedEvent의 extended lifetime promises 모두에 대해 waiting for all한 결과로 둔다.
-
waitUntilPromise의
fulfillment 시,
다음 단계를 원자적으로 수행한다:
-
registration의 state가 reregisteredWhileFiring이면:
- registration의 state를 pending으로 설정한다.
- 사용자 에이전트가 현재 online이면, registration에 대해 sync 이벤트를 발생시킨다.
- 이 단계들의 나머지를 abort한다.
- Assert: registration의 registration state는 firing이다.
- registration을 serviceWorkerRegistration의 sync registration 목록에서 제거한다.
-
registration의 state가 reregisteredWhileFiring이면:
-
waitUntilPromise의
rejection 시, 또는
service worker의
termination으로 인해
script가 abort된 경우, 다음 단계를 원자적으로 수행한다:
-
registration의 state가 reregisteredWhileFiring이면:
- registration의 state를 pending으로 설정한다.
- 사용자 에이전트가 현재 online이면, registration에 대해 sync 이벤트를 발생시킨다.
- 이 단계들의 나머지를 abort한다.
-
dispatchedEvent의
lastChance속성이 false이면, registration의 registration state를 waiting으로 설정하고, 다음 단계를 병렬로 수행한다:- 사용자 에이전트가 정의한 시간 동안 기다린다.
- registration의 registration state가 waiting이 아니면, 이 하위 단계를 abort한다.
- registration의 registration state를 pending으로 설정한다.
- 사용자 에이전트가 현재 online이면, registration에 대해 sync 이벤트를 발생시킨다.
- 그렇지 않으면 registration을 serviceWorkerRegistration의 sync registrations 목록에서 제거한다.
-
registration의 state가 reregisteredWhileFiring이면:
-
사용자 에이전트는 SyncEvent의
lifetime extension 및 execution time에 대해 일반적인 ExtendableEvent에
부과되는 제한보다 더 엄격한 시간 제한을 부과할 수 있다(MAY). 특히 lastChance가
true인 이벤트는 상당히 단축된 시간 제한을 가질 수 있다(MAY).
사용자 에이전트는 사용자 에이전트가 정의한 어떤 heuristics에 따라 sync 이벤트를 재시도한다.