私は、トレースを残すことなく、ブラウザ内の複数のタブまたはウィンドウ(CORSではなく同じドメイン上)の間で通信する方法を探していました。いくつかの解決策がありました。
最初の方法はおそらく最悪の解決策です。現在のウィンドウからウィンドウを開く必要があり、その後はウィンドウを開いたままにしておけば通信できます。いずれかのウィンドウでページをリロードすると、おそらく通信が失われます。
PostMessageを使用する2番目のアプローチは、おそらくオリジン間の通信を可能にしますが、最初のアプローチと同じ問題を抱えています。ウィンドウオブジェクトを維持する必要があります。
3番目の方法は、Cookieを使用して、同じドメインのすべてのウィンドウにメッセージを送信するように見えるデータをブラウザに保存しますが、問題は、すべてのタブが既に「メッセージ」を読んでいるかどうかがわからないことです清掃。 Cookieを定期的に読み取るには、何らかのタイムアウトを実装する必要があります。さらに、Cookieの最大長である4KBによって制限されます。
LocalStorageを使用する4番目のソリューションは、Cookieの制限を克服するように思われ、イベントを使用してリッスンすることさえできます。使用方法は、受け入れられた回答に記載されています。
2018年の編集:受け入れられた回答は引き続き機能しますが、BroadcastChannelを使用する最新のブラウザー用の新しいソリューションがあります。 BroadcastChannelを使用してタブ間でメッセージを簡単に送信する方法を説明する簡単な例については、他の回答を参照してください。
2018年編集:この目的のためにBroadcastChannelを使用した方が良いかもしれません。以下の他の回答を参照してください。しかし、タブ間の通信にlocalstorageを使用したい場合は、次のようにします:
タブが他のタブにメッセージを送信したときに通知を受けるには、単に「ストレージ」イベントにバインドする必要があります。すべてのタブで、これを行います:
$(window).on('storage', message_receive);
関数message_receive
は、他のタブでlocalStorageの値を設定するたびに呼び出されます。イベントリスナーには、localStorageに新しく設定されたデータも含まれているため、localStorageオブジェクト自体を解析する必要さえありません。これは、設定した直後に値をリセットして、トレースを効果的にクリーンアップできるため、非常に便利です。メッセージングの機能は次のとおりです。
// 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.
}
したがって、タブがonstorageイベントにバインドされ、これらの2つの関数を実装したら、次のように呼び出している他のタブに単純にメッセージをブロードキャストできます。
message_broadcast({'command':'reset'})
まったく同じメッセージを2回送信しても1回しか伝達されないため、メッセージを繰り返す必要がある場合は、次のように一意の識別子を追加してください。
message_broadcast({'command':'reset', 'uid': (new Date).getTime()+Math.random()})
また、メッセージをブロードキャストする現在のタブは実際には受信せず、同じドメイン上の他のタブまたはウィンドウのみを受信することに注意してください。
RemoveItem()の前にsetItem()を呼び出した直後に、ユーザーが別のWebページをロードするか、タブを閉じるとどうなるかを尋ねることができます。さて、私自身のテストから、ブラウザーは関数message_broadcast()
全体が完了するまでアンロードを保留にします。非常に長いfor()サイクルを入れるようにテストしましたが、クローズする前にサイクルが完了するのを待っていました。ユーザーがその間でタブを強制終了すると、ブラウザはメッセージをディスクに保存するのに十分な時間を持っていないため、このアプローチはトレースなしでメッセージを送信する安全な方法のように思えます。コメントを歓迎します。
この目的専用の最新のAPIがあります- ブロードキャストチャネル
次のように簡単です。
var bc = new BroadcastChannel('test_channel');
bc.postMessage('This is a test message.'); /* send */
bc.onmessage = function (ev) { console.log(ev); } /* receive */
メッセージが単なるDOMStringである必要はなく、あらゆる種類のオブジェクトを送信できます。
おそらく、APIのクリーンさは別として、このAPIの主な利点は、オブジェクトの文字列化がないことです。
現在 サポート はChromeおよびFirefoxでのみ使用できますが、localStorageを使用するポリフィルを見つけることができます。
JQueryに基づいていないソリューションを検索する場合、これはThomas Mが提供するソリューションの単純なJavaScriptバージョンです。
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);
}
}
チェックアウト AcrossTabs -クロスオリジンブラウザタブ間の簡単な通信postMessage と sessionStorage APIの組み合わせを使用して、通信をより簡単で信頼性の高いものにします。
さまざまなアプローチがあり、それぞれに長所と短所があります。それぞれについて説明しましょう:
長所:
短所:
長所:
短所:
データは、HTTPリクエスト(HTML、画像、JavaScript、CSSなど)ごとにサーバーに送り返され、クライアントとサーバー間のトラフィック量が増加します。
通常、以下が許可されます。
長所:
localStorage
に似ています。短所:
localStorage
と同様に、ttは same-Origin policy で動作します。そのため、保存されたデータは同じOriginでのみ使用可能になります。長所:
短所:
targetOrigin
と、メッセージリスナーに渡されるデータの健全性チェックを実装してください。PostMessage + SessionStorageの組み合わせ
PostMessageを使用して複数のタブ間で通信すると同時に、新しく開いたすべてのタブ/ウィンドウでsessionStorageを使用して、渡されるデータを保持します。タブ/ウィンドウが開いている限り、データは保持されます。そのため、オープナーのタブ/ウィンドウが閉じられたとしても、更新された後でも、開かれたタブ/ウィンドウにはデータ全体が含まれます。
AcrossTabs という名前のJavaScriptライブラリを作成しました。これはpostMessage APIを使用してクロスオリジンタブ/ウィンドウ間で通信し、 sessionStorageは、開いているタブ/ウィンドウIDが存続している限り保持します。
人々が使用を検討すべき別の方法は、共有ワーカーです。私はそれが最先端のコンセプトであることを知っていますが、ローカルストレージよりもはるかに高速で、同じOrigin上にいる限り、親/子ウィンドウ間の関係を必要としない共有ワーカーでリレーを作成できます。
私の答えを参照してください here これについての議論については。
localStorage
に基づいて、同じOriginのタブ/ウィンドウ間で同期/通信する小さなオープンソースコンポーネントがあります(免責事項-私は貢献者の1人です!)。
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
追伸イベントがほぼ同時に発生すると、ほとんどの「ロック/ミューテックス/同期」コンポーネントがWebSocket接続で失敗するため、ここでそれを推奨する自由を取りました
公式の Broadcastchannel と同等に機能するモジュールを作成しましたが、localstorage、indexeddb、unix-socketsに基づいたフォールバックがあります。これにより、WebworkersまたはNodeJSでも常に機能するようになります。 pubkey:BroadcastChannel を参照してください
ライブラリを作成しました sysend.js 、非常に小さいため、ソースコードを確認できます。ライブラリには外部依存関係はありません。
同じブラウザとドメイン内のタブ/ウィンドウ間の通信に使用できます。ライブラリは、BroadcastChannel(サポートされている場合)またはlocalStorageのストレージイベントを使用します。
APIは非常に簡単です。
sysend.on('foo', function(message) {
console.log(message);
});
sysend.broadcast('foo', {message: 'Hello'});
sysend.broadcast('foo', "hello");
sysend.broadcast('foo'); // empty notification
ブラウザがBroadcastChannelをサポートする場合、リテラルオブジェクトを送信し、そうでない場合は最初にJSONにシリアル化され、反対側で逆シリアル化されます。
最近のバージョンには、クロスドメイン通信用のプロキシを作成するヘルパーAPIもあります。 (ターゲットドメインに単一のhtmlファイルが必要です)。
デモ です。
NOTE:localStorageを使用して同じ機能を実装する場合、IEに問題があります。ストレージイベントは同じウィンドウに送信され、イベントをトリガーし、他のブラウザーでは他のタブ/ウィンドウに対してのみ呼び出されます。
私は私のブログでこれに関する記事を書きました: http://www.ebenmonney.com/blog/how-to-implement-remember-me-functionality-using-token-based-authentication-and-localstorage- in-a-web-application 。
storageManager
を作成したライブラリを使用すると、次のようにしてこれを実現できます。
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
他のシナリオを処理する他の便利な方法もあります