En 2015, nous avons introduit la synchronisation en arrière-plan, qui permet au service worker de différer le travail jusqu'à ce que l'utilisateur soit connecté. Cela signifie que l'utilisateur peut taper un message, appuyer sur "Envoyer" et quitter le site en sachant que le message sera envoyé immédiatement ou lorsqu'il aura une connexion.
Il s'agit d'une fonctionnalité utile, mais elle nécessite que le service worker soit actif pendant toute la durée de la récupération. Cela ne pose pas de problème pour les tâches courtes comme l'envoi d'un message, mais si la tâche prend trop de temps, le navigateur interrompt le service worker, car cela représente un risque pour la confidentialité et la batterie de l'utilisateur.
Que faire si vous devez télécharger un contenu qui peut prendre du temps, comme un film, des podcasts ou des niveaux de jeu ? C'est là qu'intervient Background Fetch.
Background Fetch est disponible par défaut depuis Chrome 74.
Voici une courte démonstration de deux minutes qui montre l'état traditionnel des choses par rapport à l'utilisation de Background Fetch :
Fonctionnement
Voici comment fonctionne une récupération en arrière-plan :
- Vous demandez au navigateur d'effectuer un groupe de récupérations en arrière-plan.
- Le navigateur récupère ces éléments et affiche la progression à l'utilisateur.
- Une fois la récupération terminée ou en cas d'échec, le navigateur ouvre votre service worker et déclenche un événement pour vous informer de ce qui s'est passé. C'est là que vous décidez de ce que vous allez faire des réponses, le cas échéant.
Si l'utilisateur ferme des pages de votre site après l'étape 1, ce n'est pas un problème, le téléchargement se poursuivra. Comme la récupération est très visible et facilement annulable, il n'y a pas de problème de confidentialité lié à une tâche de synchronisation en arrière-plan trop longue. Comme le service worker n'est pas exécuté en permanence, il n'y a pas lieu de craindre qu'il puisse abuser du système, par exemple en minant des bitcoins en arrière-plan.
Sur certaines plates-formes (comme Android), il est possible que le navigateur se ferme après l'étape 1, car il peut confier la récupération au système d'exploitation.
Si l'utilisateur lance le téléchargement hors connexion ou se déconnecte pendant le téléchargement, la récupération en arrière-plan est mise en pause et reprend plus tard.
L'API
Détection de caractéristiques
Comme pour toute nouvelle fonctionnalité, vous devez détecter si le navigateur la prend en charge. Pour la récupération de l'arrière-plan, il suffit de :
if ('BackgroundFetchManager' in self) {
// This browser supports Background Fetch!
}
Démarrer une récupération en arrière-plan
L'API principale dépend de l'enregistrement d'un service worker. Assurez-vous donc d'en avoir enregistré un au préalable. Ensuite :
navigator.serviceWorker.ready.then(async (swReg) => {
const bgFetch = await swReg.backgroundFetch.fetch('my-fetch', ['/ep-5.mp3', 'ep-5-artwork.jpg'], {
title: 'Episode 5: Interesting things.',
icons: [{
sizes: '300x300',
src: '/ep-5-icon.png',
type: 'image/png',
}],
downloadTotal: 60 * 1024 * 1024,
});
});
backgroundFetch.fetch
utilise trois arguments :
Paramètres | |
---|---|
id |
string identifie de manière unique cette récupération en arrière-plan.
|
requests |
Array<Request|string>
Éléments à récupérer. Les chaînes seront traitées comme des URL et transformées en Request à l'aide de new Request(theString) .
Vous pouvez récupérer des éléments d'autres origines à condition que les ressources l'autorisent via CORS. Remarque : Chrome n'est actuellement pas compatible avec les requêtes qui nécessiteraient une vérification préliminaire CORS. |
options |
Objet pouvant inclure les éléments suivants : |
options.title |
string Titre à afficher par le navigateur avec la progression. |
options.icons |
Array<IconDefinition> Tableau d'objets avec `src`, `size` et `type`. |
options.downloadTotal |
number Taille totale des corps de réponse (après décompression). Bien que cette étape soit facultative, nous vous recommandons vivement de la suivre. Il est utilisé pour indiquer à l'utilisateur la taille du téléchargement et pour fournir des informations sur la progression. Si vous ne le faites pas, le navigateur indiquera à l'utilisateur que la taille est inconnue, ce qui peut l'inciter à annuler le téléchargement. Si le nombre de téléchargements de récupération en arrière-plan dépasse le nombre indiqué ici, ils seront annulés. Il n'y a aucun problème si le téléchargement est plus petit que |
backgroundFetch.fetch
renvoie une promesse qui se résout avec un BackgroundFetchRegistration
. J'aborderai les détails plus tard. La promesse est rejetée si l'utilisateur a désactivé les téléchargements ou si l'un des paramètres fournis n'est pas valide.
En fournissant plusieurs requêtes pour une seule récupération en arrière-plan, vous pouvez combiner des éléments qui sont logiquement une seule chose pour l'utilisateur. Par exemple, un film peut être divisé en milliers de ressources (cas typique avec MPEG-DASH) et être accompagné de ressources supplémentaires comme des images. Un niveau de jeu peut être réparti sur de nombreuses ressources JavaScript, d'image et audio. Mais pour l'utilisateur, il s'agit simplement du "film" ou du "niveau".
Obtenir une récupération d'arrière-plan existante
Vous pouvez obtenir une récupération en arrière-plan existante comme suit :
navigator.serviceWorker.ready.then(async (swReg) => {
const bgFetch = await swReg.backgroundFetch.get('my-fetch');
});
…en transmettant l'ID de la récupération en arrière-plan souhaitée. get
renvoie undefined
s'il n'y a pas de récupération en arrière-plan active avec cet ID.
Une récupération en arrière-plan est considérée comme "active" à partir du moment où elle est enregistrée, jusqu'à ce qu'elle réussisse, échoue ou soit abandonnée.
Vous pouvez obtenir la liste de toutes les récupérations en arrière-plan actives à l'aide de getIds
:
navigator.serviceWorker.ready.then(async (swReg) => {
const ids = await swReg.backgroundFetch.getIds();
});
Enregistrements de récupération en arrière-plan
Un BackgroundFetchRegistration
(bgFetch
dans les exemples ci-dessus) possède les éléments suivants :
Propriétés | |
---|---|
id |
string ID de la récupération en arrière-plan. |
uploadTotal |
number Nombre d'octets à envoyer au serveur. |
uploaded |
number Nombre d'octets envoyés. |
downloadTotal |
number : valeur fournie lors de l'enregistrement de la récupération en arrière-plan ou zéro. |
downloaded |
number Nombre d'octets reçus. Cette valeur peut diminuer. Par exemple, si la connexion est interrompue et que le téléchargement ne peut pas être repris, le navigateur redémarre l'extraction de cette ressource à partir de zéro. |
result |
Choisissez l'une des options suivantes :
|
failureReason |
Choisissez l'une des options suivantes :
|
recordsAvailable |
boolean Est-il possible d'accéder aux requêtes/réponses sous-jacentes ? Une fois cette valeur définie sur "false", |
Méthodes | |
abort() |
Renvoie Promise<boolean> . Annule la récupération en arrière-plan. La promesse renvoyée est résolue avec la valeur "true" si la récupération a été correctement annulée. |
matchAll(request, opts) |
Renvoie Promise<Array<BackgroundFetchRecord>> Obtenez les requêtes et les réponses. Les arguments sont les mêmes que ceux de l'API Cache. L'appel sans arguments renvoie une promesse pour tous les enregistrements. Pour en savoir plus, reportez-vous aux informations ci-dessous. |
match(request, opts) |
Renvoie Promise<BackgroundFetchRecord> Comme ci-dessus, mais résout avec la première correspondance. |
Événements | |
progress |
Déclenché lorsque l'une des valeurs uploaded , downloaded , result ou failureReason change. |
Suivre la progression
Pour ce faire, utilisez l'événement progress
. N'oubliez pas que downloadTotal
correspond à la valeur que vous avez fournie ou à 0
si vous n'en avez pas fourni.
bgFetch.addEventListener('progress', () => {
// If we didn't provide a total, we can't provide a %.
if (!bgFetch.downloadTotal) return;
const percent = Math.round(bgFetch.downloaded / bgFetch.downloadTotal * 100);
console.log(`Download progress: ${percent}%`);
});
Obtenir les requêtes et les réponses
bgFetch.match('/ep-5.mp3').then(async (record) => {
if (!record) {
console.log('No record found');
return;
}
console.log(`Here's the request`, record.request);
const response = await record.responseReady;
console.log(`And here's the response`, response);
});
record
est un BackgroundFetchRecord
et se présente comme suit :
Propriétés | |
---|---|
request |
Request : requête fournie. |
responseReady |
Promise<Response> Réponse récupérée. La réponse est derrière une promesse, car elle n'a peut-être pas encore été reçue. La promesse sera rejetée si la récupération échoue. |
Événements Service Worker
Événements | |
---|---|
backgroundfetchsuccess |
Tout a été récupéré avec succès. |
backgroundfetchfailure |
Échec d'une ou de plusieurs extractions. |
backgroundfetchabort |
Échec d'une ou de plusieurs récupérations.
Cela n'est vraiment utile que si vous souhaitez nettoyer les données associées. |
backgroundfetchclick |
L'utilisateur a cliqué sur l'UI de progression du téléchargement. |
Les objets d'événement contiennent les éléments suivants :
Propriétés | |
---|---|
registration |
BackgroundFetchRegistration |
Méthodes | |
updateUI({ title, icons }) |
Vous permet de modifier le titre et les icônes que vous avez définis au départ. Cette étape est facultative, mais elle vous permet de fournir plus de contexte si nécessaire. Vous ne pouvez le faire qu'*une seule fois* pendant les événements backgroundfetchsuccess et backgroundfetchfailure . |
Réagir en cas de réussite ou d'échec
Nous avons déjà vu l'événement progress
, mais il n'est utile que lorsque l'utilisateur a une page de votre site ouverte. Le principal avantage de la récupération en arrière-plan est que les éléments continuent de fonctionner après que l'utilisateur a quitté la page ou même fermé le navigateur.
Si la récupération en arrière-plan se termine correctement, votre service worker recevra l'événement backgroundfetchsuccess
et event.registration
sera l'enregistrement de la récupération en arrière-plan.
Après cet événement, les requêtes et réponses récupérées ne sont plus accessibles. Si vous souhaitez les conserver, déplacez-les vers un emplacement tel que l'API Cache.
Comme pour la plupart des événements de service worker, utilisez event.waitUntil
pour que le service worker sache quand l'événement est terminé.
Par exemple, dans votre service worker :
addEventListener('backgroundfetchsuccess', (event) => {
const bgFetch = event.registration;
event.waitUntil(async function() {
// Create/open a cache.
const cache = await caches.open('downloads');
// Get all the records.
const records = await bgFetch.matchAll();
// Copy each request/response across.
const promises = records.map(async (record) => {
const response = await record.responseReady;
await cache.put(record.request, response);
});
// Wait for the copying to complete.
await Promise.all(promises);
// Update the progress notification.
event.updateUI({ title: 'Episode 5 ready to listen!' });
}());
});
L'échec peut être dû à une seule erreur 404, qui n'est peut-être pas importante pour vous. Il peut donc être intéressant de copier certaines réponses dans un cache, comme indiqué ci-dessus.
Réagir à un clic
L'UI affichant la progression et le résultat du téléchargement est cliquable. L'événement backgroundfetchclick
dans le service worker vous permet de réagir à cela. Comme indiqué ci-dessus, event.registration
sera l'enregistrement de récupération en arrière-plan.
L'action courante à effectuer avec cet événement consiste à ouvrir une fenêtre :
addEventListener('backgroundfetchclick', (event) => {
const bgFetch = event.registration;
if (bgFetch.result === 'success') {
clients.openWindow('/latest-podcasts');
} else {
clients.openWindow('/download-progress');
}
});
Ressources supplémentaires
Correction : une version précédente de cet article indiquait à tort que Background Fetch était une "norme Web". L'API ne fait actuellement pas partie de la piste des normes. La spécification est disponible dans WICG en tant que rapport provisoire du groupe de la communauté.