Français

Explorez la puissance du Background Sync des Service Workers pour des expériences hors ligne fiables. Apprenez techniques et stratégies.

Maîtriser les Service Workers : Une plongée dans le Background Sync

Dans le monde connecté d'aujourd'hui, les utilisateurs s'attendent à des expériences fluides, même lorsque leur connexion Internet est peu fiable. Les Service Workers fournissent la base pour créer des applications "offline-first", et le Background Sync pousse cette capacité encore plus loin. Ce guide complet explore les subtilités du Background Sync, offrant des aperçus pratiques et des stratégies d'implémentation pour les développeurs du monde entier.

Qu'est-ce que le Background Sync des Service Workers ?

Le Background Sync est une API web qui permet aux Service Workers de différer des actions jusqu'à ce que l'utilisateur dispose d'une connexion réseau stable. Imaginez un utilisateur composant un e-mail dans un train avec un accès Internet intermittent. Sans le Background Sync, l'e-mail pourrait ne pas être envoyé, entraînant une expérience frustrante. Le Background Sync garantit que l'e-mail est mis en file d'attente et envoyé automatiquement lorsque la connexion est rétablie.

Avantages clés :

Comment fonctionne le Background Sync

Le processus implique plusieurs étapes :

  1. Enregistrement : Votre application web enregistre un événement de synchronisation auprès du Service Worker. Cela peut être déclenché par une action de l'utilisateur (par exemple, la soumission d'un formulaire) ou par programme.
  2. Différé : Si le réseau est indisponible, le Service Worker reporte l'événement de synchronisation jusqu'à ce qu'une connexion soit détectée.
  3. Synchronisation : Lorsque le navigateur détecte une connexion réseau stable, il réveille le Service Worker et déclenche l'événement de synchronisation.
  4. Exécution : Le Service Worker exécute le code associé à l'événement de synchronisation, envoyant généralement des données à un serveur.
  5. Retentatives : Si la synchronisation échoue (par exemple, en raison d'une erreur serveur), le navigateur retentera automatiquement l'événement de synchronisation plus tard.

Mise en œuvre du Background Sync : un guide étape par étape

Étape 1 : Enregistrement des événements de synchronisation

La première étape consiste à enregistrer un événement de synchronisation nommé. Ceci est généralement effectué dans le code JavaScript de votre application web. Voici un exemple :


  navigator.serviceWorker.ready.then(function(swRegistration) {
    return swRegistration.sync.register('my-sync');
  }).then(function() {
    console.log('Sync registered!');
  }).catch(function() {
    console.log('Sync registration failed!');
  });

Remplacez `'my-sync'` par un nom descriptif pour votre événement de synchronisation. Ce nom sera utilisé pour identifier l'événement dans votre Service Worker.

Étape 2 : Gestion des événements de synchronisation dans le Service Worker

Ensuite, vous devez écouter l'événement de synchronisation dans votre Service Worker et gérer la logique de synchronisation. Voici un exemple :


  self.addEventListener('sync', function(event) {
    if (event.tag === 'my-sync') {
      event.waitUntil(
        doSomeStuff()
      );
    }
  });

  function doSomeStuff() {
    return new Promise(function(resolve, reject) {
        // Effectuez ici la logique de synchronisation réelle
        // Exemple : envoyer des données à un serveur
        fetch('/api/data', {
          method: 'POST',
          body: JSON.stringify({data: 'some data'})
        }).then(function(response) {
          if (response.ok) {
            console.log('Sync successful!');
            resolve();
          } else {
            console.error('Sync failed:', response.status);
            reject();
          }
        }).catch(function(error) {
          console.error('Sync error:', error);
          reject();
        });
    });
  }

Explication :

Étape 3 : Stockage des données pour la synchronisation

Dans de nombreux cas, vous devrez stocker les données localement pendant que l'utilisateur est hors ligne, puis les synchroniser lorsqu'une connexion devient disponible. IndexedDB est une API de navigateur puissante pour stocker des données structurées hors ligne.

Exemple : Stockage des données de formulaire dans IndexedDB


  // Fonction pour stocker les données du formulaire dans IndexedDB
  function storeFormData(data) {
    return new Promise(function(resolve, reject) {
      let request = indexedDB.open('my-db', 1);

      request.onerror = function(event) {
        console.error('IndexedDB error:', event);
        reject(event);
      };

      request.onupgradeneeded = function(event) {
        let db = event.target.result;
        let objectStore = db.createObjectStore('form-data', { keyPath: 'id', autoIncrement: true });
      };

      request.onsuccess = function(event) {
        let db = event.target.result;
        let transaction = db.transaction(['form-data'], 'readwrite');
        let objectStore = transaction.objectStore('form-data');

        let addRequest = objectStore.add(data);

        addRequest.onsuccess = function(event) {
          console.log('Form data stored in IndexedDB');
          resolve();
        };

        addRequest.onerror = function(event) {
          console.error('Error storing form data:', event);
          reject(event);
        };

        transaction.oncomplete = function() {
          db.close();
        };
      };
    });
  }

  // Fonction pour récupérer toutes les données du formulaire depuis IndexedDB
  function getAllFormData() {
    return new Promise(function(resolve, reject) {
      let request = indexedDB.open('my-db', 1);

      request.onerror = function(event) {
        console.error('IndexedDB error:', event);
        reject(event);
      };

      request.onsuccess = function(event) {
        let db = event.target.result;
        let transaction = db.transaction(['form-data'], 'readonly');
        let objectStore = transaction.objectStore('form-data');
        let getAllRequest = objectStore.getAll();

        getAllRequest.onsuccess = function(event) {
          let formData = event.target.result;
          resolve(formData);
        };

        getAllRequest.onerror = function(event) {
          console.error('Error retrieving form data:', event);
          reject(event);
        };

        transaction.oncomplete = function() {
          db.close();
        };
      };
    });
  }

  // Exemple d'utilisation : lors de la soumission du formulaire
  document.getElementById('myForm').addEventListener('submit', function(event) {
    event.preventDefault();

    let formData = {
      name: document.getElementById('name').value,
      email: document.getElementById('email').value,
      message: document.getElementById('message').value
    };

    storeFormData(formData)
      .then(function() {
        // Facultatif, enregistrer un événement de synchronisation pour envoyer les données plus tard
        navigator.serviceWorker.ready.then(function(swRegistration) {
          return swRegistration.sync.register('form-submission');
        });
      })
      .catch(function(error) {
        console.error('Error storing form data:', error);
      });
  });

Étape 4 : Gestion de la synchronisation des données

Dans le service worker, récupérez toutes les données du formulaire depuis IndexedDB et envoyez-les au serveur.


  self.addEventListener('sync', function(event) {
    if (event.tag === 'form-submission') {
      event.waitUntil(
        getAllFormData()
          .then(function(formData) {
            // Envoyer chaque donnée de formulaire au serveur
            return Promise.all(formData.map(function(data) {
              return fetch('/api/form-submission', {
                method: 'POST',
                body: JSON.stringify(data),
                headers: {
                  'Content-Type': 'application/json'
                }
              })
              .then(function(response) {
                if (response.ok) {
                  // Données envoyées avec succès, supprimez-les d'IndexedDB
                  return deleteFormData(data.id);
                } else {
                  console.error('Failed to send form data:', response.status);
                  throw new Error('Failed to send form data'); // Cela déclenchera une nouvelle tentative
                }
              });
            }));
          })
          .then(function() {
            console.log('All form data synced successfully!');
          })
          .catch(function(error) {
            console.error('Error syncing form data:', error);
          })
      );
    }
  });

  function deleteFormData(id) {
    return new Promise(function(resolve, reject) {
        let request = indexedDB.open('my-db', 1);

        request.onerror = function(event) {
          console.error('IndexedDB error:', event);
          reject(event);
        };

        request.onsuccess = function(event) {
          let db = event.target.result;
          let transaction = db.transaction(['form-data'], 'readwrite');
          let objectStore = transaction.objectStore('form-data');
          let deleteRequest = objectStore.delete(id);

          deleteRequest.onsuccess = function(event) {
            console.log('Form data deleted from IndexedDB');
            resolve();
          };

          deleteRequest.onerror = function(event) {
            console.error('Error deleting form data:', event);
            reject(event);
          };

          transaction.oncomplete = function() {
            db.close();
          };
        };
    });
  }

Stratégies avancées de Background Sync

Synchronisation périodique en arrière-plan

La synchronisation périodique en arrière-plan vous permet de planifier des événements de synchronisation à intervalles réguliers, même lorsque l'utilisateur n'utilise pas activement l'application. Ceci est utile pour des tâches telles que la récupération des derniers titres d'actualités ou la mise à jour des données mises en cache. Cette fonctionnalité nécessite l'autorisation de l'utilisateur et HTTPS.

Enregistrement :


  navigator.serviceWorker.ready.then(function(swRegistration) {
    return swRegistration.periodicSync.register('periodic-sync', {
      minInterval: 24 * 60 * 60 * 1000, // 1 jour
    });
  });

Gestion de l'événement :


  self.addEventListener('periodicsync', function(event) {
    if (event.tag === 'periodic-sync') {
      event.waitUntil(
        // Effectuez la tâche de synchronisation périodique
        updateNewsHeadlines()
      );
    }
  });

Détection de l'état du réseau

Il est crucial de vérifier l'état du réseau avant de tenter de synchroniser des données. La propriété `navigator.onLine` indique si le navigateur est actuellement en ligne. Vous pouvez également écouter les événements `online` et `offline` pour détecter les changements de connectivité réseau.


  window.addEventListener('online',  function(e) {
    console.log("Went online");
  });

  window.addEventListener('offline', function(e) {
    console.log("Went offline");
  });

Stratégies de nouvelle tentative

Le Background Sync fournit des mécanismes de nouvelle tentative automatiques. Si une synchronisation échoue, le navigateur retentera l'événement ultérieurement. Vous pouvez configurer le comportement de nouvelle tentative à l'aide des options `networkState` et `maximumRetryTime`.

Meilleures pratiques pour le Background Sync

Considérations globales pour le Background Sync

Lors du développement d'applications pour un public mondial, tenez compte des points suivants :

Cas d'utilisation du Background Sync

Débogage du Background Sync

Chrome DevTools offre un excellent support pour le débogage des Service Workers et du Background Sync. Vous pouvez utiliser le panneau Application pour inspecter l'état du Service Worker, afficher les événements de synchronisation et simuler des conditions hors ligne.

Alternatives au Background Sync

Bien que le Background Sync soit un outil puissant, il existe des approches alternatives pour gérer la synchronisation des données hors ligne :

Conclusion

Le Service Worker Background Sync est un outil précieux pour créer des applications web robustes et fiables qui offrent une expérience utilisateur transparente, même dans des conditions réseau difficiles. En comprenant les concepts et les techniques décrits dans ce guide, vous pouvez exploiter efficacement le Background Sync pour améliorer vos applications et répondre à un public mondial.

N'oubliez pas de donner la priorité à l'expérience utilisateur, de gérer les erreurs avec élégance et d'être conscient de l'impact sur la batterie lors de la mise en œuvre du Background Sync. En suivant les meilleures pratiques et en tenant compte des facteurs mondiaux, vous pouvez créer des applications véritablement accessibles et fiables pour les utilisateurs du monde entier.

Alors que les technologies web évoluent, il est essentiel de rester informé des dernières avancées. Explorez la documentation officielle des Service Workers et du Background Sync, et expérimentez différentes stratégies d'implémentation pour trouver la meilleure approche pour vos besoins spécifiques. Le pouvoir du développement "offline-first" est entre vos mains – adoptez-le !