2 min read

Background Sync API

The Background Sync API allows web applications to defer actions until the user has stable connectivity. This ensures that whatever the user wants to send is eventually sent, even if the user closes the application or goes offline.

1. The Concept

When a user performs an action (like sending a message) while offline, the request usually fails. With Background Sync, you register a "sync" task. The Service Worker listens for this event and executes the task as soon as the browser detects a connection, even if the page is closed.

2. Registering a Sync

You register a sync event from your main page (or any window context) using the ServiceWorkerRegistration.

// Check for support
if ('serviceWorker' in navigator && 'SyncManager' in window) {
  navigator.serviceWorker.ready.then(async (registration) => {
    try {
      // Register a sync event with a specific tag
      await registration.sync.register('send-messages');
      console.log('Sync registered!');
    } catch (err) {
      console.log('Sync registration failed:', err);
    }
  });
}

3. Handling the Sync Event

The Service Worker listens for the sync event. The tag property identifies which sync event fired.

// service-worker.js
self.addEventListener('sync', (event) => {
  if (event.tag === 'send-messages') {
    event.waitUntil(sendOutboxMessages());
  }
});

async function sendOutboxMessages() {
  // 1. Get messages from IndexedDB (outbox)
  const messages = await getMessagesFromOutbox();

  // 2. Send them to the server
  for (const msg of messages) {
    try {
      await fetch('/api/messages', {
        method: 'POST',
        body: JSON.stringify(msg)
      });
      // 3. Remove from outbox if successful
      await removeMessageFromOutbox(msg.id);
    } catch (error) {
      console.error('Sending failed:', error);
      // If this promise rejects, the sync event is considered failed 
      // and will be retried by the browser later.
      throw error; 
    }
  }
}

4. event.waitUntil()

It is crucial to pass a Promise to event.waitUntil().

  • If the Promise resolves, the sync is considered successful.
  • If the Promise rejects, the sync is considered failed. The browser will reschedule the sync event to try again later (with exponential backoff).

5. Use Cases

  • Chat Apps: Sending messages written while offline.
  • Social Media: Posting photos or status updates.
  • Analytics: Ensuring tracking data reaches the server.
  • Forms: Saving data entered while offline.

programming/javascript/vanilla/javascript programming/javascript/vanilla/service-workers-and-pwa programming/javascript/vanilla/indexeddb