Communication entre les onglets ou windows
je cherchais un moyen de communiquer entre plusieurs onglets ou fenêtres dans un navigateur (sur le même domaine, pas CORS) sans laisser de traces. Il y avait plusieurs solutions:
la première est probablement la pire solution - vous devez ouvrir une fenêtre de votre fenêtre actuelle et ensuite vous pouvez communiquer seulement tant que vous gardez les fenêtres ouvertes. Si vous rechargez la page dans l'une des fenêtres, vous avez probablement perdu la communication.
deuxième approche, en utilisant postMessage, permet probablement la communication d'origine croisée, mais souffre du même problème que la première approche. Vous devez maintenir un objet de fenêtre.
troisième le problème est que vous ne pouvez jamais savoir si tous les onglets lire le "message" déjà ou pas avant de nettoyer. Vous devez implémenter une sorte de timeout pour lire le cookie périodiquement. En outre, vous êtes limité par la longueur maximale des cookies, qui est de 4KB.
quatrième solution, en utilisant localStorage, a semblé surmonter les limites de cookies, et il peut être même écouter-à l'aide d'événements. La façon de l'utiliser est décrite dans la réponse acceptée.
Modifier 2018: la accepté de répondre fonctionne toujours, mais il existe une nouvelle solution pour les navigateurs modernes, l'utilisation BroadcastChannel. Voir l'autre réponse pour un exemple simple décrivant comment transmettre facilement un message entre des onglets en utilisant BroadcastChannel.
8 réponses
Modifier 2018: Vous pouvez mieux utiliser BroadcastChannel à cette fin, voir les autres réponses ci-dessous. Pourtant, si vous préférez toujours utiliser localstorage pour la communication entre les onglets, faites - le de cette façon:
pour être notifié lorsqu'un onglet envoie un message à d'autres onglets, vous devez simplement vous lier à l'événement 'storage'. Dans tous les onglets, faites ceci:
$(window).on('storage', message_receive);
La fonction message_receive
sera appelée à chaque fois que vous définissez une valeur de localStorage dans tout autre onglet. L'écouteur d'événements contient aussi les données nouvellement définies à localStorage, de sorte que vous n'avez même pas besoin de parser l'objet localStorage lui-même. C'est très pratique car vous pouvez réinitialiser la valeur juste après qu'elle ait été définie, pour nettoyer efficacement les traces. Voici les fonctions de messagerie:
// use local storage for messaging. Set message in local storage and clear it right away
// This is a safe way how to communicate with other tabs while not leaving any traces
//
function message_broadcast(message)
{
localStorage.setItem('message',JSON.stringify(message));
localStorage.removeItem('message');
}
// receive message
//
function message_receive(ev)
{
if (ev.originalEvent.key!='message') return; // ignore other keys
var message=JSON.parse(ev.originalEvent.newValue);
if (!message) return; // ignore empty msg or msg reset
// here you act on messages.
// you can send objects like { 'command': 'doit', 'data': 'abcd' }
if (message.command == 'doit') alert(message.data);
// etc.
}
donc maintenant que vos onglets se lient sur l'événement onstorage, et que vous avez ces deux fonctions implémentées, vous pouvez simplement diffuser un message à d'autres onglets appelant, par exemple:
message_broadcast({'command':'reset'})
N'oubliez pas qu'envoyer exactement le même message deux fois ne se propagera qu'une seule fois, donc si vous avez besoin de répéter les messages, ajoutez un identifiant unique, comme
message_broadcast({'command':'reset', 'uid': (new Date).getTime()+Math.random()})
se rappeler aussi que l'onglet courant qui diffuse le message ne le reçoit pas réellement, seulement d'autres onglets ou fenêtres sur le même domaine.
vous pouvez demander ce qui se passe si l'utilisateur charge une page Web différente ou ferme son onglet juste après l'appel setItem() avant le removeItem(). D'après mes propres tests, le navigateur met le déchargement en attente jusqu'à ce que toute la fonction message_broadcast()
soit terminée. J'ai testé pour y mettre quelques très long pour() cycle et il a encore attendu la fin du cycle avant de fermer. Si l'utilisateur tue l'onglet juste entre les deux, alors le navigateur n'aura pas assez de temps pour enregistrer le message sur le disque, donc cette approche me semble être une façon sûre d'envoyer des messages sans aucune trace. Commentaires bienvenus.
Il ya une API moderne dédiée à cet effet - canal de diffusion
C'est aussi simple que:
var bc = new BroadcastChannel('test_channel');
bc.postMessage('This is a test message.'); /* send */
bc.onmessage = function (ev) { console.log(ev); } /* receive */
il n'est pas nécessaire que le message soit simplement un dominateur, tout type d'objet peut être envoyé.
probablement, en dehors de la propreté API, c'est le principal avantage de cette API - aucune stringification d'objet.
actuellement pris en charge seulement dans Chrome et Firefox, mais vous pouvez trouver un polyfill qui utilise localStorage.
pour ceux qui cherchent une solution non basée sur jQuery, il s'agit d'une version JavaScript simple de la solution fournie par Thomas M:
window.addEventListener("storage", message_receive);
function message_broadcast(message) {
localStorage.setItem('message',JSON.stringify(message));
}
function message_receive(ev) {
if (ev.key == 'message') {
var message=JSON.parse(ev.newValue);
}
}
check-out AcrossTabs - communication facile entre les onglets du navigateur cross-origin. il utilise une combinaison de postMessage et sessionStorage API pour rendre la communication beaucoup plus facile et fiable.
il existe différentes approches et chacune présente ses avantages et ses inconvénients. Permet de discuter de chaque:
-
Pros :
- le stockage Web peut être considéré de façon simpliste comme une amélioration des cookies, offrant une capacité de stockage beaucoup plus grande. Si vous regardez le code source de Mozilla nous pouvons voir que 5120KB ( 5MB qui égale 2,5 millions les caractères sur Chrome) est la taille de stockage par défaut pour un domaine entier. Cela vous donne beaucoup plus d'espace pour travailler qu'un cookie 4KB typique.
- les données ne sont pas renvoyées au serveur pour chaque requête HTTP (HTML, images, JavaScript, CSS, etc) - réduisant le volume de trafic entre le client et le serveur.
- les données stockées dans localStorage persistent jusqu'à leur suppression explicite. Les modifications apportées sont sauvegardées et disponibles pour tous les prochaines visites sur le site.
Cons :
- Il travaille sur same-origin policy . Ainsi, les données stockées ne seront disponibles que sur la même origine.
-
Pour:
- comparé à d'autres, il n'y a rien D'AFAIK.
Inconvénients:
- La 4K limite pour l'ensemble du cookie, y compris le nom, valeur, date d'expiration, etc. Pour prendre en charge la plupart des navigateurs, garder le nom sous 4000 octets, et la taille globale des cookies Sous 4093 octets.
-
les données sont renvoyées au serveur pour chaque requête HTTP (HTML, images, JavaScript, CSS, etc.) - augmenter le volume de trafic entre le client et le serveur.
typiquement, les éléments suivants sont autorisés:
- 300 cookies au total
- 4096 octets par témoin
- 20 cookies par domaine
- 81920 octets par Domaine(20 cookies de taille maximale 4096 = 81920 octets).)
-
Pour:
- Il est semblable à
localStorage
.
Les modifications - ne sont disponibles que par fenêtre (ou onglet dans les navigateurs comme Chrome et Firefox). Les modifications apportées sont sauvegardées et disponibles pour la page actuelle, ainsi que pour les prochaines visites pour le site sur la même fenêtre. Une fois la fenêtre fermée ,le stockage est supprimé
Inconvénients:
- les données ne sont disponibles que dans la fenêtre/l'onglet dans lequel elles ont été placées.
- les données ne sont pas persistantes, c'est-à-dire qu'elles seront perdues une fois la fenêtre/l'onglet fermé.
- Comme
localStorage
, tt fonctionne sur la same-origin policy . Ainsi, les données stockées pourrez uniquement disponible sur la même origine.
- Il est semblable à
-
Pour:
- Sécurité active "les 15191490920" cross-origin de la communication.
- en tant que point de données, la mise en œuvre de WebKit (utilisée par Safari et Chrome) n'impose actuellement aucune limite (autres que celles imposées par la perte de mémoire).
Inconvénients:
- besoin d'ouvrir une fenêtre à partir de la fenêtre actuelle et ne peut communiquer que si vous gardez les fenêtres ouvertes.
- " Security concerns - L'envoi de chaînes via postMessage est que vous allez récupérer d'autres événements postMessage publié par D'autres JavaScript plugins, alors assurez-vous d'implémenter un
targetOrigin
et un contrôle de santé mentale pour les données transmises à l'auditeur des messages.
-
Une combinaison de PostMessage + SessionStorage
utilisant postMessage pour communiquer entre plusieurs onglets et en même temps utilisant sessionStorage dans tous les onglets/fenêtres nouvellement ouverts pour persister données étant passé. Les données persisteront tant que les onglets/fenêtres resteront ouverts. Ainsi, même si l'onglet/Fenêtre d'ouverture est fermée, les onglets/fenêtres ouvertes auront toutes les données même après avoir été rafraîchies.
j'ai écrit une bibliothèque JavaScript pour cela, nommé AcrossTabs qui utilise L'API postMessage pour communiquer entre les onglets d'origine croisée / windows et sessionStorage pour persister l'ouvert onglets/fenêtres identité aussi longtemps qu'ils vivent.
une autre méthode que les gens devraient envisager d'utiliser est les travailleurs partagés. Je sais que c'est un concept de pointe, mais vous pouvez créer un relais sur un travailleur partagé qui est beaucoup plus rapide que localstorage, et ne nécessite pas une relation entre la fenêtre parent/enfant, tant que vous êtes sur la même origine.
Voir ma réponse ici pour une discussion que j'ai faite à ce sujet.
il y a un petit composant open-source pour synchroniser/communiquer entre les onglets/fenêtres de la même origine (disclaimer - i'm one of the contributors!) basé sur localStorage
.
TabUtils.BroadcastMessageToAllTabs("eventName", eventDataString);
TabUtils.OnBroadcastMessage("eventName", function (eventDataString) {
DoSomething();
});
TabUtils.CallOnce("lockname", function () {
alert("I run only once across multiple tabs");
});
https://github.com/jitbit/TabUtils
P. S. j'ai pris la liberté de le recommander ici car la plupart des composants "lock / mutex / sync" ne fonctionnent pas sur les connexions websocket lorsque les événements se produisent presque simultanément
j'ai créé un module qui fonctionne à l'égal du canal de diffusion officiel mais a des retombées basées sur localstorage, indexeddb et unix-sockets. Cela fait en sorte qu'il fonctionne toujours, même avec les Webworkers ou NodeJS. Voir pubkey: BroadcastChannel
j'ai écrit un article à ce sujet sur mon blog: http://www.ebenmonney.com/blog/how-to-implement-remember-me-functionality-using-token-based-authentication-and-localstorage-in-a-web-application .
en utilisant une bibliothèque que j'ai créé storageManager
vous pouvez atteindre ce qui suit:
storageManager.savePermanentData('data', 'key'): //saves permanent data
storageManager.saveSyncedSessionData('data', 'key'); //saves session data to all opened tabs
storageManager.saveSessionData('data', 'key'); //saves session data to current tab only
storageManager.getData('key'); //retrieves data
il y a aussi d'autres méthodes pratiques pour gérer d'autres scénarios