הדרך המודרנית
סנכרון תקופתי ברקע מאפשר לכם להציג תוכן עדכני כשמפעילים אפליקציית Progressive Web App או דף שנתמך על ידי Service Worker. היא עושה את זה על ידי הורדת נתונים ברקע כשהאפליקציה או הדף לא בשימוש.
שימוש ב-Periodic Background Sync API
אחרי שמתקינים את Service Worker, משתמשים ב-Permissions API כדי לשלוח שאילתה לגבי periodic-background-sync. אפשר לעשות את זה מחלון או מהקשר של service worker.
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 גורם מטפל באירועים ל-קובץ שירות (service worker). אובייקט האירוע שמועבר אליו יכיל פרמטר תג שתואם לערך שבו השתמשתם במהלך ההרשמה. לדוגמה, אם סנכרון תקופתי ברקע נרשם עם השם 'content-sync', אז event.tag יהיה 'content-sync'.
self.addEventListener('periodicsync', (event) => {
if (event.tag === 'content-sync') {
event.waitUntil(syncContent());
}
});
תאימות דפדפן
הדרך הקלאסית
במקום לעדכן את הנתונים ברקע כדי שהם יהיו מוכנים כשהמשתמש טוען את האפליקציה, השיטה הקלאסית פשוט כוללת עדכון של הנתונים בזמן הטעינה.
קריאה נוספת
- חוויה עשירה יותר באופליין עם Periodic Background Sync API
- Web Periodic Background Synchronization API
הדגמה (דמו)
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);
});
}