Daten regelmäßig im Hintergrund synchronisieren

Cecilia Cong
Cecilia Cong

Die moderne Art

Durch die regelmäßige Hintergrundsynchronisierung können Sie neue Inhalte anzeigen, wenn eine progressive Web-App oder eine von Dienst-Worker gesicherte Seite gestartet wird. Dabei werden Daten im Hintergrund heruntergeladen, wenn die App oder Seite nicht verwendet wird.

Verwenden der Periodic Background Sync API

Verwenden Sie nach der Installation des Service Workers die Permissions API, um periodic-background-sync abzufragen. Dies ist entweder in einem Fenster- oder in einem Service Worker-Kontext möglich.

const status = await navigator.permissions.query({
  name: 'periodic-background-sync',
});
if (status.state === 'granted') {
  // Periodic background sync can be used.
} else {
  // Periodic background sync cannot be used.
}

Für die Registrierung einer regelmäßigen Synchronisierung sind sowohl ein Tag als auch ein minimales Synchronisierungsintervall (minInterval) erforderlich. Das Tag identifiziert die registrierte Synchronisierung, sodass mehrere Synchronisierungen registriert werden können. Im folgenden Beispiel lautet der Tag-Name 'content-sync' und der minInterval ein Tag.

navigator.serviceWorker.ready.then(async registration => {
  try {
    await registration.periodicSync.register('get-cats', { minInterval: 24 * 60 * 60 * 1000 });
    console.log(Periodic background sync registered.');
  } catch (err) {
    console.error(err.name, err.message);
  }
});

Rufe periodicSync.getTags() auf, um ein Array von Registrierungs-Tags abzurufen. Im folgenden Beispiel werden Tag-Namen verwendet, um zu bestätigen, dass die Cache-Aktualisierung aktiv ist, damit keine weiteren Aktualisierungen durchgeführt werden.

const registration = await navigator.serviceWorker.ready;
if ('periodicSync' in registration) {
  const tags = await registration.periodicSync.getTags();
  // Only update content if sync isn't set up.
  if (!tags.includes('content-sync')) {
    updateContentOnPageLoad();
  }
} else {
  // If periodic background sync isn't supported, always update.
  updateContentOnPageLoad();
}

Wenn Sie auf eine regelmäßige Hintergrundsynchronisierung reagieren möchten, fügen Sie Ihrem Service Worker einen periodicsync-Event-Handler hinzu. Das an dieses Ereignis übergebene Ereignisobjekt enthält einen Tag-Parameter, der mit dem bei der Registrierung verwendeten Wert übereinstimmt. Wenn beispielsweise eine regelmäßige Hintergrundsynchronisierung mit dem Namen 'content-sync' registriert wurde, ist event.tag 'content-sync'.

self.addEventListener('periodicsync', (event) => {
  if (event.tag === 'content-sync') {
    event.waitUntil(syncContent());
  }
});

Browserkompatibilität

Unterstützte Browser

  • 80
  • 80
  • x
  • x

Quelle

Klassisch

Anstatt Daten im Hintergrund zu aktualisieren, damit sie bereit sind, wenn der Nutzer die App lädt, besteht die klassische Methode einfach darin, die Daten beim Laden zu aktualisieren.

Weitere Informationen

Demo

HTML

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link
      rel="icon"
      href=""
    />
    <link rel="manifest" href="./manifest.json" />
    <title>How to periodically synchronize data in the background</title>
    <link rel="stylesheet" href="/style.css" />
    <!-- TODO: Devsite - Removed inline handlers -->
    <!-- <script src="/script.js" defer></script> -->
  </head>
  <body>
    <h1>How to periodically synchronize data in the background</h1>
    <p class="available">Periodic background sync can be used. Install the app first.</p>
    <p class="not-available">Periodic background sync cannot be used.</p>
    <h2>Last updated</h2>
    <p class="last-updated">Never</p>
    <h2>Registered tags</h2>
    <ul>
      <li>None yet.</li>
    </ul>
  </body>
</html>

CSS


        html {
  box-sizing: border-box;
  font-family: system-ui, sans-serif;
  color-scheme: dark light;
}

*,
*:before,
*:after {
  box-sizing: inherit;
}

body {
  margin: 1rem;
}
        

JS


        const available = document.querySelector('.available');
const notAvailable = document.querySelector('.not-available');
const ul = document.querySelector('ul');
const lastUpdated = document.querySelector('.last-updated');

const updateContent = async () => {
  const data = await fetch(
    'https://worldtimeapi.org/api/timezone/Europe/London.json'
  ).then((response) => response.json());
  return new Date(data.unixtime * 1000);
};

const registerPeriodicBackgroundSync = async (registration) => {
  const status = await navigator.permissions.query({
    name: 'periodic-background-sync',
  });
  if (status.state === 'granted' && 'periodicSync' in registration) {
    try {
      // Register the periodic background sync.
      await registration.periodicSync.register('content-sync', {
        // An interval of one day.
        minInterval: 24 * 60 * 60 * 1000,
      });
      available.hidden = false;
      notAvailable.hidden = true;

      // List registered periodic background sync tags.
      const tags = await registration.periodicSync.getTags();
      if (tags.length) {
        ul.innerHTML = '';
      }
      tags.forEach((tag) => {
        const li = document.createElement('li');
        li.textContent = tag;
        ul.append(li);
      });

      // Update the user interface with the last periodic background sync data.
      const backgroundSyncCache = await caches.open('periodic-background-sync');
      if (backgroundSyncCache) {
        const backgroundSyncResponse =
          backgroundSyncCache.match('/last-updated');
        if (backgroundSyncResponse) {
          lastUpdated.textContent = `${await fetch('/last-updated').then(
            (response) => response.text()
          )} (periodic background-sync)`;
        }
      }

      // Listen for incoming periodic background sync messages.
      navigator.serviceWorker.addEventListener('message', async (event) => {
        if (event.data.tag === 'content-sync') {
          lastUpdated.textContent = `${await updateContent()} (periodic background sync)`;
        }
      });
    } catch (err) {
      console.error(err.name, err.message);
      available.hidden = true;
      notAvailable.hidden = false;
      lastUpdated.textContent = 'Never';
    }
  } else {
    available.hidden = true;
    notAvailable.hidden = false;
    lastUpdated.textContent = `${await updateContent()} (manual)`;
  }
};

if ('serviceWorker' in navigator) {
  window.addEventListener('load', async () => {
    const registration = await navigator.serviceWorker.register('./sw.js');
    console.log('Service worker registered for scope', registration.scope);

    await registerPeriodicBackgroundSync(registration);
  });
}