Nowoczesny sposób
Okresowa synchronizacja w tle umożliwia wyświetlanie nowych treści po uruchomieniu progresywnej aplikacji internetowej lub strony wspieranej przez skrypt service worker. Dane są pobierane w tle, gdy nie korzystasz ze strony lub aplikacji.
Korzystanie z interfejsu Periodic Background Sync API
Po zainstalowaniu skryptu service worker użyj interfejsu Permissions API, aby przesłać zapytanie o periodic-background-sync
. Możesz to zrobić w oknie lub w kontekście skryptu 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.
}
Zarejestrowanie okresowej synchronizacji wymaga zarówno tagu, jak i minimalnego odstępu czasu synchronizacji (minInterval
). Tag identyfikuje zarejestrowaną synchronizację, aby umożliwić zarejestrowanie wielu synchronizacji. W poniższym przykładzie nazwa tagu to 'content-sync'
, a minInterval
to jeden dzień.
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);
}
});
Wywołaj periodicSync.getTags()
, aby pobrać tablicę tagów rejestracji. W przykładzie poniżej używamy nazw tagów, aby potwierdzić, że aktualizacja pamięci podręcznej jest aktywna, i uniknąć ponownej aktualizacji.
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();
}
Aby odpowiedzieć na okresowe zdarzenie synchronizacji w tle, dodaj moduł obsługi zdarzeń periodicsync
do skryptu service worker. Przekazany do niego obiekt zdarzenia będzie zawierał parametr tagu pasujący do wartości użytej podczas rejestracji. Jeśli na przykład okresowa synchronizacja w tle została zarejestrowana pod nazwą 'content-sync'
, event.tag
będzie mieć wartość 'content-sync'
.
self.addEventListener('periodicsync', (event) => {
if (event.tag === 'content-sync') {
event.waitUntil(syncContent());
}
});
Zgodność z przeglądarką
Klasyczny sposób
Zamiast aktualizować dane w tle, aby były gotowe, gdy użytkownik załaduje aplikację, klasyczny sposób polega po prostu na aktualizacji danych podczas wczytywania.
Więcej informacji
- Więcej możliwości w trybie offline dzięki interfejsowi Periodic Background Sync API
- Web Periodic Background Synchronization API
Pokaz
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);
});
}