Façons de synchroniser les onglets du navigateur



Il y a longtemps, dans une galaxie lointaine, une tâche semblait synchroniser les onglets du navigateur pour un lecteur web, comme VK: il fallait organiser l'échange de données entre les onglets, suivre leur nombre et assigner des tâches à certains d'entre eux. L'implémentation entière devait être effectuée sur le client. De nombreuses informations ont été collectées et saisies dans un article entier.

Ci-dessous, je décrirai différentes façons de résoudre ces problèmes.

Considérez les moyens les plus populaires de synchroniser les onglets du navigateur par ordre croissant de complexité.

Stockage local


localStorage - le stockage local, une propriété de l'objet window, vous permet d'accéder à l'objet Storage local. Il peut stocker des données entre les sessions utilisateur. Il existe une propriété similaire - sessionStorage , mais elle ne stocke les données que pour la durée de la session de page.
Les données sont ajoutées au stockage à l'aide de la méthode setItem .

localStorage.setItem('key', 'value'); 

L'événement de stockage est idéal pour synchroniser les données entre les onglets; il est généré lorsque la valeur de l'élément localStorage ou sessionStorage change.

 window.addEventListener('storage', function(event) { console.log(event.key); }); 

L'événement ne fonctionne pas sur l'onglet, ce qui apporte des modifications, mais se déclenche sur les autres onglets du domaine dans le navigateur.

Génération d'événements de stockage

Les navigateurs ont différents niveaux de stockage pour localStorage et sessionStorage:

  • Chrome, FireFox et Opera ~ 5 Mo.
  • IE ~ 4,8 Mo.
  • iOS Safari, OS X Safari ~ 2,5 Mo.
  • Android ~ 5 Mo.

Parmi les lacunes, on peut noter le volume de stockage du navigateur, et lorsqu'il est plein, un nouvel objet ne sera pas enregistré.
La méthode fonctionne dans tous les navigateurs sauf Opera mini .

Poster un message


postMessage est une méthode qui vous permet d'envoyer en toute sécurité des demandes interdomaines , c'est-à-dire de communiquer entre elles vers des fenêtres et des iframes de différents domaines.
Il est très pratique pour l'interaction de widgets externes et de services connectés via iframe à partir de la page principale.
Transmission des messages:

 const win = window.frames.target; win.postMessage('send message', 'http://javascript.ru'); 

Les données transmises peuvent être tout objet prenant en charge le clonage (chaîne, objet, tableau, carte, date ...). Mais IE ne prend en charge que les chaînes.

L'URL indique que seules les fenêtres de cette source peuvent recevoir des messages.
Pour recevoir des messages, la fenêtre doit s'abonner à l'événement onmessage.

 window.addEventListener('message', function(event) { if (event.origin != 'http://javascript.ru') { return; } console.log(event.data); }); 

N'importe quelle fenêtre peut accéder à cette méthode pour lui envoyer un message, quel que soit l'emplacement du document dans la fenêtre. Par conséquent, assurez-vous de vérifier l'origine.

Dans IE, l'interface postMessage fonctionne uniquement avec les iframes et ne fonctionne pas entre les onglets et les fenêtres.

API de canal de diffusion


L'API Broadcast Channel fournit un lien simple entre le contexte de visualisation (fenêtres, onglets). L'objet BroadcastChannel crée un canal commun qui vous permet de recevoir tout message qui lui est envoyé. Les onglets, les fenêtres, les iframes peuvent s'abonner à la chaîne et établir une connexion avec elle.

 const bc = new BroadcastChannel('test_channel'); 

La méthode postMessage publie un message sur le canal. L'argument est un type qui prend en charge le clonage .

 bc.postMessage('This is a test message.'); 

Lorsqu'un message est publié, un événement de message sera envoyé à chaque objet connecté à ce canal.

 bc.addEventListener('message', function (e) { console.log(e); }) 


Publiez un message sur un canal pour différents contextes.

L'API est assez simple, elle peut être considérée comme un simple bus de messages. Mais la méthode a un sérieux inconvénient: il n'y a pas de support pour Safari et IE .

À première vue, vous pouvez trouver plusieurs méthodes similaires de transfert de données (par exemple MessageChannel, WebSocket), mais chacune d'elles sert un objectif spécifique - leur comparaison .

Travailleurs Web


Il s'agit d'un mécanisme qui permet à un script de s'exécuter dans un thread d'arrière-plan distinct du thread principal d'une application Web. Il est implémenté à l'aide de fichiers js, qui sont inclus dans la page à l'aide d'une requête HTTP asynchrone.

Les travailleurs sont parfaits pour effectuer des opérations informatiques lourdes sans ralentir l'interface utilisateur.
Mais avec la synchronisation, seuls deux types de travailleurs peuvent aider.

Travailleur partagé


Il s'agit d'un type particulier de travailleur accessible à partir de plusieurs contextes de navigateur. Écrivons un fichier js partagé pour les onglets, par exemple shared-worker.js.

 const worker = new SharedWorker('shared-worker.js'); 

Chaque onglet peut communiquer avec le travailleur via worker.port. Le script du travailleur a également accès à ses ports. Chaque fois que l'onglet se connecte au travailleur, l'événement connect est déclenché dans le script.

 // shared-worker.js const connections = []; onconnect = function(e) { const port = e.ports[0]; connections.push(port); }; 

La méthode postMessage a été créée pour envoyer des données de tabulation à un travailleur partagé.

 worker.port.postMessage('test message'); 

Vous pouvez récupérer des données de travailleur à l'aide de l'événement de message.

 worker.port.onmessage = function (e) { console.log(e.data); }; 

Il y a un événement de connexion dans l'API SharedWorker, mais il n'y a pas d'événement de déconnexion, et donc les données ne pourront pas s'auto-nettoyer dans les onglets fermés - elles continueront d'être considérées comme ouvertes. Cela ne conduira pas à des erreurs, mais cela peut être considéré comme une faille ou une API de fonctionnalité.

Fonctionne uniquement dans Chrome et FF .

Travailleur des services


Il s'agit d'un travailleur événementiel qui peut surveiller, intercepter et modifier les demandes réseau et les mettre en cache.
Inscription des travailleurs:

 if ('serviceWorker' in navigator) { navigator.serviceWorker.register('service-worker.js') .then(function() { return navigator.serviceWorker.ready; }) .catch(function(error) { console.error('registration error : ', error); }); } 

À l'aide de l'événement de message, les onglets peuvent recevoir des données du fichier js de travail et la fonction syncTabState est utilisée pour traiter le message.

 self.addEventListener('message', function(e){ const data = e.data; const tabId = e.source.id self.syncTabState(data, tabId); }); 

La fonction sendTabState est conçue pour envoyer des messages aux onglets.

 self.sendTabState = function(client, data){ client.postMessage(data); } 

Utilisation détaillée et nombreux exemples ici .

Tous les travailleurs Web n'ont pas accès aux objets fenêtre et document.

Le technicien de service ne fonctionne pas dans IE et Opera mini .

Bibliothèques de synchronisation


C'est un moyen pour ceux qui ne veulent pas faire du vélo et qui sont prêts à considérer les solutions existantes.


Leur inconvénient est que les bibliothèques sont généralement universelles, elles ne conviennent donc pas toujours aux solutions étroites.

Résumé


Pour résumer, comparons visuellement les méthodes de prise en charge du navigateur.


Utilisez LocalStorage, BroadcastChannel et PostMessage pour les cas simples lorsque vous devez envoyer un message à plusieurs fenêtres / onglets ou iframes potentiellement.

Les travailleurs partagés et les travailleurs de service sont les solutions les plus appropriées pour gérer les verrous d'état partagés et les fichiers partagés.

Et pour la tâche avec le lecteur Web, LocalStorage a été sélectionné, car il existe un support pour IE.
J'espère que cet article vous a aidé à choisir la bonne méthode de synchronisation.

Je remercie l'équipe des affiches pour son aide et son soutien!

Articles d'occasion:

Source: https://habr.com/ru/post/fr422545/


All Articles