Veriler arka planda düzenli olarak nasıl senkronize edilir?

Cecilia Cong
Cecilia Cong

Modern yöntem

Düzenli arka plan senkronizasyonu, bir progresif web uygulaması veya hizmet çalışanı destekli sayfa açıldığında yeni içerik göstermenize olanak tanır. Bunu, uygulama veya sayfa kullanılmadığında arka planda veri indirerek yapar.

Periodic Background Sync API'yi kullanma

Hizmet çalışanı yüklendikten sonra periodic-background-sync için sorgu yapmak üzere Permissions API'yi kullanın. Bunu bir pencere veya hizmet çalışanı bağlamında yapabilirsiniz.

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.
}

Periyodik senkronizasyon kaydetmek için hem bir etiket hem de minimum bir senkronizasyon aralığı (minInterval) gerekir. Etiket, birden fazla senkronizasyonun kaydedilebilmesi için kayıtlı senkronizasyonu tanımlar. Aşağıdaki örnekte etiket adı 'content-sync', minInterval ise bir gündür.

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);
  }
});

Bir kayıt etiketi dizisi almak için periodicSync.getTags() işlevini çağırın. Aşağıdaki örnekte, tekrar güncellemeyi önlemek için önbelleğin güncellenmesinin etkin olduğunu onaylamak üzere etiket adları kullanılmaktadır.

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();
}

Periyodik arka plan senkronizasyonu etkinliğine yanıt vermek için hizmet işleyicinize bir periodicsync etkinlik işleyici ekleyin. Ona iletilen etkinlik nesnesi, kayıt sırasında kullanılan değerle eşleşen bir etiket parametresi içerir. Örneğin, 'content-sync' adıyla periyodik bir arka plan senkronizasyonu kaydedilmişse event.tag, 'content-sync' olur.

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

Tarayıcı uyumluluğu

Tarayıcı desteği

  • Chrome: 80.
  • Edge: 80.
  • Firefox: Desteklenmez.
  • Safari: Desteklenmez.

Kaynak

Klasik yöntem

Klasik yöntem, kullanıcı uygulamayı yüklediğinde hazır olması için verileri arka planda güncellemek yerine verileri yükleme sırasında güncellemekten ibarettir.

Daha fazla bilgi

Demo

HTMLCSSJS
<!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>

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

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

body {
  margin: 1rem;
}
        

        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);
  });
}