איך לסנכרן נתונים מדי פעם ברקע

Cecilia Cong
Cecilia Cong

הדרך המודרנית

סנכרון תקופתי ברקע מאפשר לכם להציג תוכן עדכני כשאפליקציית Progressive Web App או דף שתומך בשירות עובדים מופעלים. כדי לעשות זאת, המערכת מורידת נתונים ברקע כשלא משתמשים באפליקציה או בדף.

שימוש ב-Periodic Background Sync API

אחרי שתתקינו את ה-service worker, תוכלו להשתמש ב-Permissions API כדי לשלוח שאילתה לגבי periodic-background-sync. אפשר לעשות זאת מתוך חלון או מהקשר של שירות עובד.

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

כדי לרשום סנכרון תקופתי, צריך גם תג וגם מרווח סנכרון מינימלי (minInterval). התג מזהה את הסנכרון הרשום, כך שאפשר לרשום כמה סנכרונים. בדוגמה הבאה, שם התג הוא 'content-sync' ו-minInterval הוא יום אחד.

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

קוראים לפונקציה periodicSync.getTags() כדי לאחזר מערך של תגי רישום. בדוגמה הבאה נעשה שימוש בשמות התגים כדי לוודא שעדכון המטמון פעיל, וכך למנוע עדכון חוזר.

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

כדי להגיב לאירוע סנכרון תקופתי ברקע, מוסיפים ל-service worker טיפול באירוע periodicsync. אובייקט האירוע שיעבור אליו יכיל פרמטר תג שתואם לערך ששימש במהלך ההרשמה. לדוגמה, אם סנכרון תקופתי ברקע נרשם בשם 'content-sync', הערך של event.tag יהיה 'content-sync'.

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

תאימות דפדפן

תמיכה בדפדפנים

  • Chrome: ‏ 80.
  • Edge: ‏ 80.
  • Firefox: לא נתמך.
  • Safari: לא נתמך.

מקור

הדרך הקלאסית

במקום לעדכן את הנתונים ברקע כדי שהם יהיו מוכנים כשהמשתמש יטען את האפליקציה, בדרך הקלאסית הנתונים מתעדכנים פשוט בזמן הטעינה.

קריאה נוספת

הדגמה (דמו)

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