كيفية مزامنة البيانات بشكل دوري في الخلفية

Cecilia Cong
Cecilia Cong

الطريقة الحديثة

تتيح لك المزامنة الدورية للخلفية عرض محتوى جديد عند إطلاق تطبيق ويب تقدّمي أو صفحة يدعمها عامل خدمة. ويتم ذلك عن طريق تنزيل البيانات في الخلفية عندما لا يتم استخدام التطبيق أو الصفحة.

استخدام واجهة برمجة التطبيقات التي تستخدم ميزة "مزامنة الخلفية الدورية"

بعد تثبيت مشغّل الخدمات، استخدِم 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();
}

للاستجابة لحدث دوري في الخلفية للمزامنة، أضِف معالج أحداث periodicsync إلى مشغّل الخدمة. سيحتوي عنصر الحدث الذي يتم تمريره إليه على مَعلمة علامة تتطابق مع القيمة المستخدَمة أثناء التسجيل. على سبيل المثال، إذا تم تسجيل مزامنة دورية في الخلفية بالاسم 'content-sync'، سيصبح event.tag عندها 'content-sync'.

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

توافُق المتصفح

التوافق مع المتصفح

  • 80
  • 80
  • x
  • x

المصدر

الطريقة الكلاسيكية

بدلاً من تحديث البيانات في الخلفية بحيث تكون جاهزة عند تحميل المستخدم للتطبيق، تتكون الطريقة الكلاسيكية ببساطة من تحديث البيانات عند التحميل.

محتوى إضافي للقراءة

الخصائص الديموغرافية

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