Présentation de la synchronisation en arrière-plan

Jake Archibld
Jake Archibald

La synchronisation en arrière-plan est une nouvelle API Web qui vous permet de différer les actions jusqu'à ce que l'utilisateur dispose d'une connectivité stable. Cela garantit que tout ce que l'utilisateur souhaite envoyer est réellement envoyé.

Problème

Internet est un endroit idéal pour perdre du temps. Sans perdre de temps sur Internet, nous ne pourrions pas savoir que les chats n'aiment pas les fleurs, les caméléons adorent les bulles, ou que notre propre Eric Bidelman est un héros du putt putt de la fin des années 90.

Mais parfois, parfois, nous ne cherchons pas à perdre du temps. L'expérience utilisateur souhaitée se présente plutôt comme suit:

  1. Votre téléphone sort de votre poche.
  2. Atteindre un objectif mineur.
  3. Le téléphone dans la poche.
  4. Reprendre la vie.

Malheureusement, cette expérience est souvent perturbée en raison d'une mauvaise connectivité. Nous sommes tous passés par là. Vous êtes face à un écran blanc ou une icône de chargement. Vous savez que vous devriez simplement abandonner et continuer votre vie, mais vous laissez 10 secondes supplémentaires au cas où. Au bout de 10 secondes ? Rien.

Mais pourquoi abandonner maintenant ? Vous avez déjà investi du temps, donc partir sans rien serait du gaspillage, alors vous continuez d'attendre. À ce stade, vous voulez abandonner, mais vous savez que la seconde où vous le faites est la seconde avant que tout ne se charge si vous seul attendiez.

Les service workers résolvent le problème de chargement de page en vous permettant de diffuser du contenu à partir d'un cache. Mais que se passe-t-il lorsque la page doit envoyer quelque chose au serveur ?

Pour le moment, si l'utilisateur clique sur "Envoyer" dans un message, il doit regarder une icône de chargement jusqu'à la fin de l'opération. S'ils essaient de quitter l'onglet ou de le fermer, nous utilisons onbeforeunload pour afficher un message du type : "Non, j'ai besoin que vous regardiez davantage cette icône de chargement. Désolé". Si l'utilisateur n'est pas connecté, nous lui indiquons "Désolé, vous devez réessayer plus tard".

C'est nul. La synchronisation en arrière-plan vous permet de gagner en efficacité.

Solution

La vidéo suivante montre Emojoy, une démo de chat uniquement emoji. Il s'agit d'une application Web progressive qui fonctionne principalement hors connexion. L'application utilise des messages push et des notifications, ainsi que la synchronisation en arrière-plan.

Si l'utilisateur tente d'envoyer un message alors qu'il n'a pas de connexion, heureusement, le message est envoyé en arrière-plan une fois qu'il est connecté à Internet.

Depuis mars 2016, la synchronisation en arrière-plan est disponible dans Chrome à partir de la version 49. Pour la voir, procédez comme suit:

  1. Ouvrez Emojoy.
  2. Déconnectez-vous (en mode Avion ou en vous rendant dans votre cage Faraday locale).
  3. Saisissez un message.
  4. Revenez à l'écran d'accueil (vous pouvez fermer l'onglet ou le navigateur).
  5. Connectez-vous à Internet.
  6. Le message est envoyé en arrière-plan.

Ce type d'envoi en arrière-plan permet également d'être perçu comme une amélioration des performances. L'application n'a pas besoin de se soucier de l'envoi des messages. Elle peut donc ajouter immédiatement le message à la sortie.

Demander une synchronisation en arrière-plan

Dans un véritable style Web extensible, il s'agit d'une fonctionnalité de bas niveau qui vous donne la liberté de faire ce dont vous avez besoin. Vous demandez le déclenchement d'un événement lorsque l'utilisateur dispose d'une connectivité, c'est-à-dire immédiat si l'utilisateur dispose déjà d'une connectivité. Vous écoutez ensuite cet événement et faites ce que vous avez à faire.

Comme pour les messages push, il utilise un service worker comme cible de l'événement, ce qui lui permet de fonctionner lorsque la page n'est pas ouverte. Pour commencer, enregistrez une synchronisation depuis une page:

// Register your service worker:
navigator.serviceWorker.register('/sw.js');

// Then later, request a one-off sync:
navigator.serviceWorker.ready.then(function(swRegistration) {
  return swRegistration.sync.register('myFirstSync');
});
 ```

Then listen for the event in `/sw.js`:

```js
self.addEventListener('sync', function(event) {
  if (event.tag == 'myFirstSync') {
    event.waitUntil(doSomeStuff());
  }
});

Voilà, c'est terminé ! Dans ce qui précède, doSomeStuff() doit renvoyer une promesse indiquant la réussite ou l'échec de l'opération. Si l'opération aboutit, la synchronisation est terminée. En cas d'échec, une nouvelle tentative de synchronisation est planifiée. Les nouvelles synchronisations attendent également la connectivité et utilisent un intervalle exponentiel entre les tentatives.

Le nom de la balise de la synchronisation ("myFirstSync" dans l'exemple ci-dessus) doit être unique pour une synchronisation donnée. Si vous enregistrez une synchronisation en utilisant le même tag qu'une synchronisation en attente, celle-ci sera fusionnée avec la synchronisation existante. Cela signifie que vous pouvez vous inscrire à une synchronisation de "vidage de la boîte d'envoi" chaque fois que l'utilisateur envoie un message, mais s'il envoie cinq messages hors connexion, vous n'obtiendrez qu'une synchronisation lorsqu'il se connectera. Si vous souhaitez créer cinq événements de synchronisation distincts, il vous suffit d'utiliser des tags uniques.

Voici une démonstration simple qui fait le strict minimum : l'événement de synchronisation permet d'afficher une notification.

À quoi sert la synchronisation en arrière-plan ?

Idéalement, vous devriez l'utiliser pour planifier l'envoi de données qui vous intéressent au-delà de la durée de vie de la page. Messages de chat, e-mails, mises à jour de documents, modifications de paramètres, importation de photos... tout ce que vous souhaitez atteindre sur le serveur, même si l'utilisateur quitte l'onglet ou le ferme. La page peut les stocker dans un magasin de "boîte d'envoi" de la base de données indexée, et le service worker les récupère et les envoie.

Mais tu peux aussi l'utiliser pour récupérer de petites quantités de données...

Nouvelle démonstration !

Voici la démo Wikipédia hors connexion que j'ai créée pour l'objectif Supercharging Page Load (Recharger le chargement de la page). J'y ai depuis ajouté une touche de synchronisation en arrière-plan.

Essayez par vous-même. Assurez-vous d'utiliser Chrome 49 ou une version ultérieure, puis:

  1. Accédez à n'importe quel article, par exemple Chrome.
  2. Déconnectez-vous (en mode Avion ou en rejoignant un service hors connexion comme celui que j'ai déjà).
  3. Cliquez sur un lien vers un autre article.
  4. Un message vous indique que la page n'a pas réussi à se charger (ce message apparaît également si le chargement prend un certain temps).
  5. Acceptez les notifications.
  6. Fermez le navigateur.
  7. Se connecter
  8. Vous recevrez une notification lorsque l'article sera téléchargé, mis en cache et prêt à être consulté.

Grâce à ce schéma, l'utilisateur peut mettre son téléphone dans sa poche et se concentrer sur sa vie, en sachant qu'il recevra une alerte lorsqu'il le récupérera comme il le souhaite.

Autorisations

Les démonstrations que j'ai indiquées utilisent des notifications Web, qui nécessitent une autorisation, contrairement à la synchronisation en arrière-plan.

Les événements de synchronisation se terminent souvent lorsqu'une page est ouverte sur le site. Par conséquent, l'autorisation de l'utilisateur nuit à l'expérience utilisateur. Nous limitons plutôt les cas où les synchronisations peuvent être enregistrées et déclenchées pour éviter les abus. Exemple :

  • Vous ne pouvez vous inscrire à un événement de synchronisation que si l'utilisateur a ouvert une fenêtre sur le site.
  • La durée d'exécution de l'événement étant limitée, vous ne pouvez pas les utiliser pour pinguer un serveur toutes les x secondes, extraire des bitcoins ou autre.

Bien sûr, ces restrictions peuvent se resserrer ou se resserrer en fonction de l'utilisation réelle.

amélioration progressive

Il faudra un certain temps avant que tous les navigateurs ne soient compatibles avec la synchronisation en arrière-plan, d'autant plus que Safari et Edge ne prennent pas encore en charge les service workers. Mais l'amélioration progressive est utile dans ce cas:

if ('serviceWorker' in navigator && 'SyncManager' in window) {
  navigator.serviceWorker.ready.then(function(reg) {
    return reg.sync.register('tag-name');
  }).catch(function() {
    // system was unable to register for a sync,
    // this could be an OS-level restriction
    postDataFromThePage();
  });
} else {
  // serviceworker/sync not supported
  postDataFromThePage();
}

Si les service workers ou la synchronisation en arrière-plan ne sont pas disponibles, publiez simplement le contenu de la page comme vous le feriez aujourd'hui.

Il est utile d'utiliser la synchronisation en arrière-plan même si l'utilisateur semble disposer d'une bonne connectivité, car elle vous protège contre les navigations et les fermetures d'onglets lors de l'envoi de données.

L'avenir

Au cours du premier semestre 2016, nous prévoyons de déployer la synchronisation en arrière-plan dans une version stable de Chrome, tout en travaillant sur une variante, la "synchronisation périodique en arrière-plan". Avec la synchronisation périodique en arrière-plan, vous pouvez demander un événement limité selon l'intervalle de temps, l'état de la batterie et l'état du réseau. L'autorisation de l'utilisateur serait nécessaire, et c'est également le navigateur qui déterminera quand et à quelle fréquence ces événements se déclencheront. En d'autres termes, un site d'actualités peut demander à se synchroniser toutes les heures, mais le navigateur peut savoir que vous ne lisez ce site qu'à 7h00, et la synchronisation se déclenchera tous les jours à 6h50. Cette idée est un peu plus éloignée que la synchronisation ponctuelle, mais elle arrivera bientôt.

Progressivement, nous intégrons sur le Web des modèles populaires d'Android et d'iOS, tout en conservant ce qui le rend si intéressant.