Améliorer la fermeture des pages dans XMLHttpRequest synchrone

Joe Medley
Joe Medley

Il est courant qu'une page ou une application comporte des données analytiques ou d'autres données non envoyées au moment où un utilisateur la ferme. Pour éviter toute perte de données, certains sites utilisent un appel synchrone à XMLHttpRequest() pour maintenir la page ou l'application ouverte jusqu'à ce que ses données soient transmises au serveur. Non seulement il existe de meilleures façons d'enregistrer des données, mais cette technique crée une mauvaise expérience utilisateur en retardant la fermeture de la page de plusieurs secondes.

Cette pratique doit changer, et les navigateurs y répondent. La spécification XMLHttpRequest() est déjà prévue pour l'abandon et la suppression. Chrome 80 franchit la première étape en interdisant les appels synchrones dans plusieurs gestionnaires d'événements, en particulier beforeunload, unload, pagehide et visibilitychange lorsqu'ils sont déclenchés lors de la fermeture. WebKit a également récemment validé un commit implémentant la même modification de comportement.

Je vais décrire brièvement les options pour ceux qui ont besoin de temps pour mettre à jour leurs sites et présenter les alternatives à XMLHttpRequest().

Désactivations temporaires

Chrome souhaite donner aux développeurs le temps de ne plus dépendre de XMLHttpRequest(). C'est pourquoi nous avons proposé des options de désactivation temporaires.

Participez à un test d'origine. Vous ajoutez ainsi un jeton spécifique à l'origine dans les en-têtes de votre page, ce qui permet les appels XMLHttpRequest() synchrones. Cette option prendra fin peu avant la sortie de Chrome 89, en mars 2021. Les clients Chrome Enterprise peuvent également utiliser le flag de règle AllowSyncXHRInPageDismissal, qui se termine en même temps.

Autres solutions

Quelle que soit la façon dont vous renvoyez les données au serveur, il est préférable d'éviter d'attendre le déchargement de la page pour envoyer toutes les données en même temps. En plus de créer une mauvaise expérience utilisateur, la décharge n'est pas fiable sur les navigateurs modernes et risque d'entraîner une perte de données en cas de problème. Plus précisément, les événements de déchargement ne se déclenchent souvent pas sur les navigateurs mobiles, car il existe de nombreuses façons de fermer un onglet ou un navigateur sur les systèmes d'exploitation mobiles sans que l'événement unload ne se déclenche. Avec XMLHttpRequest(), l'utilisation de petites charges utiles était un choix. Il est désormais obligatoire. Les deux alternatives ont une limite d'importation de 64 Ko par contexte, comme l'exige la spécification.

Keepalive de récupération

L'API Fetch fournit un moyen robuste de gérer les interactions avec le serveur et une interface cohérente à utiliser avec différentes API de plate-forme. Parmi ses options figure keepalive, qui garantit qu'une requête se poursuit, que la page qui l'a envoyée reste ouverte ou non :

window.addEventListener('unload', {
  fetch('/siteAnalytics', {
    method: 'POST',
    body: getStatistics(),
    keepalive: true
  });
}

La méthode fetch() présente l'avantage de mieux contrôler ce qui est envoyé au serveur. Ce que je ne montre pas dans l'exemple, c'est que fetch() renvoie également une promesse qui se résout avec un objet Response. Comme j'essaie de ne pas gêner le déchargement de la page, j'ai choisi de ne rien faire avec.

SendBeacon()

SendBeacon() utilise en fait l'API Fetch en coulisses, c'est pourquoi elle présente la même limite de charge utile de 64 Ko et garantit également qu'une requête se poursuit après le déchargement d'une page. Son principal avantage est sa simplicité. Il vous permet d'envoyer vos données avec une seule ligne de code :

window.addEventListener('unload', {
  navigator.sendBeacon('/siteAnalytics', getStatistics());
}

Conclusion

Avec la disponibilité accrue de fetch() dans les navigateurs, XMLHttpRequest() sera, espérons-le, supprimé de la plate-forme Web. Les fournisseurs de navigateurs conviennent qu'il doit être supprimé, mais cela prendra du temps. La suppression de l'un de ses pires cas d'utilisation est une première étape qui améliore l'expérience utilisateur pour tous.