La méthode moderne
La synchronisation en arrière-plan périodique vous permet d'afficher du contenu récent lorsqu'une progressive web app ou une page de service basée sur un worker est lancée. Pour ce faire, il télécharge des données en arrière-plan lorsque l'application ou la page n'est pas utilisée.
Utiliser l'API Periodic Background Sync
Une fois le service worker installé, utilisez l'API Permissions pour interroger periodic-background-sync
. Vous pouvez le faire depuis une fenêtre ou un contexte de 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.
}
L'enregistrement d'une synchronisation périodique nécessite à la fois une balise et un intervalle de synchronisation minimal (minInterval
). La balise identifie la synchronisation enregistrée afin que plusieurs synchronisations puissent être enregistrées. Dans l'exemple ci-dessous, le nom de la balise est 'content-sync'
et la minInterval
correspond à un jour.
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);
}
});
Appelez periodicSync.getTags()
pour récupérer un tableau de balises d'enregistrement. L'exemple ci-dessous utilise des noms de balise pour confirmer que la mise à jour du cache est active afin d'éviter une nouvelle mise à jour.
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();
}
Pour répondre à un événement de synchronisation en arrière-plan périodique, ajoutez un gestionnaire d'événements periodicsync
à votre worker de service. L'objet d'événement qui lui est transmis contiendra un paramètre de balise correspondant à la valeur utilisée lors de l'enregistrement. Par exemple, si une synchronisation en arrière-plan périodique a été enregistrée avec le nom 'content-sync'
, event.tag
sera 'content-sync'
.
self.addEventListener('periodicsync', (event) => {
if (event.tag === 'content-sync') {
event.waitUntil(syncContent());
}
});
Compatibilité du navigateur
Méthode classique
Plutôt que de mettre à jour les données en arrière-plan pour qu'elles soient prêtes lorsque l'utilisateur charge l'application, la méthode classique consiste simplement à mettre à jour les données lors du chargement.
Documentation complémentaire
- Expériences hors connexion plus riches avec l'API Periodic Background Sync
- API Web Periodic Background Synchronization
Démo
<!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);
});
}