This section is non-normative.
Web Applications often run in environments with unreliable networks (e.g., mobile phones) and unknown lifetimes (the browser might be killed or the user might navigate away). This makes it difficult to synchronize client data from web apps (such as photo uploads, document changes, or composed emails) with servers. If the browser closes or the user navigates away before synchronization can complete, the app must wait until the user revisits the page to try again. This specification provides a new onsync service worker event which can fire in the background so that synchronization attempts can continue despite adverse conditions when initially requested. This API is intended to reduce the time between content creation and content synchronization with the server.
As this API relies on service workers, functionality provided by this API is only available in a secure context.
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 :(' ); }); }
In the above example addChatMessageToOutbox
is a developer-defined function.
Reacting to a sync event within a service worker:
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' )) }) ); } });
In the above example getMessagesFromOutbox
and removeMessagesFromOutbox
are developer-defined functions.
The sync event is considered to run in the background if no service worker clients whose frame type is top-level or auxiliary exist for the origin of the corresponding service worker registration.
The user agent is considered to be online if the user agent has established a network connection. A user agent MAY use a stricter definition of being online. Such a stricter definition MAY take into account the particular service worker or origin a sync registration is associated with.
A sync registration is a tuple consisting of a tag and a state.
A sync registration has an associated tag, a DOMString.
A sync registration has an associated registration state, which is one of pending, waiting, firing, or reregisteredWhileFiring. It is initially set to pending.
A sync registration has an associated service worker registration. It is initially set to null.
Within one list of sync registrations each sync registration MUST have a unique tag.
Note: Background sync SHOULD be enabled by default. Having the permission denied is considered an exceptional case.
partial interface ServiceWorkerRegistration {readonly attribute SyncManager ; };
sync
The
attribute exposes a sync
SyncManager
, which has an associated service worker registration represented by the ServiceWorkerRegistration
on which the attribute is exposed.
[Exposed =(Window ,Worker )]interface {
SyncManager Promise <void >register (DOMString );
tag Promise <sequence <DOMString >>getTags (); };
The
method, when invoked, MUST return a new promise promise and run the following steps in parallel:register(tag)
The
method when invoked, MUST return a new promise promise and run the following steps in parallel:getTags()
partial interface ServiceWorkerGlobalScope {attribute EventHandler ; }; [
onsync (
Constructor DOMString ,
type SyncEventInit ),
init Exposed =ServiceWorker ]interface :
SyncEvent ExtendableEvent {readonly attribute DOMString ;
tag readonly attribute boolean ; };
lastChance dictionary :
SyncEventInit ExtendableEventInit {required DOMString ;
tag boolean =
lastChance false ; };
Note: The SyncEvent
interface represents a firing sync registration. If the page (or worker) that registered the event is running, the user agent will fire the sync event as soon as network connectivity is available. Otherwise, the user agent should run the event at the soonest convenience. If a sync event fails, the user agent may decide to retry it at a time of its choosing. The lastChance
attribute is true if the user agent will not make further attempts to try this sync after the current attempt.
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; }) ); } });
The above example reacts to lastChance
by showing a notification to the user. This requires the origin to have permission to show notifications.
In the above example doImportantThing
is a developer-defined function.
Whenever the user agent changes to online, the user agent SHOULD fire a sync event for each sync registration whose registration state is pending. The events may be fired in any order.
To fire a sync event for a sync registration registration, the user agent MUST run the following steps:
- Assert: registration’s registration state is pending.
- Let serviceWorkerRegistration be the service worker registration associated with registration.
- Assert: registration exists in the list of sync registrations associated with serviceWorkerRegistration.
- Set registration’s registration state to firing.
-
Fire Functional Event "
sync
" usingSyncEvent
on serviceWorkerRegistration with the following properties:tag
- The tag associated with registration
lastChance
- False if the user agent will retry this sync event if it fails, or true if no further attempts will be made after the current attempt.
Then run the following steps with dispatchedEvent:
A user agent MAY impose a time limit on the lifetime extension and execution time of a SyncEvent
which is stricter than the time limit imposed for ExtendableEvent
s in general. In particular an event for which lastChance
is true MAY have a significantly shortened time limit.
A user agent will retry a sync event based on some user agent defined heuristics.