これまでのところ、1 つのウィンドウが 1 種類のメッセージを送信し、もう 1 つのウィンドウがメッセージを 1 つの方法で解釈する postmessage のチュートリアルしか見ていません。
ウィンドウ間でさまざまな種類の対話を行いたい場合、postmessage でそれを処理できますか?
それは、postmessage がすべきことの粒度に反しているのでしょうか?
たとえば、カスタム コールバックを送受信できるようにしたい場合はどうすればよいでしょうか。
これまでのところ、1 つのウィンドウが 1 種類のメッセージを送信し、もう 1 つのウィンドウがメッセージを 1 つの方法で解釈する postmessage のチュートリアルしか見ていません。
ウィンドウ間でさまざまな種類の対話を行いたい場合、postmessage でそれを処理できますか?
それは、postmessage がすべきことの粒度に反しているのでしょうか?
たとえば、カスタム コールバックを送受信できるようにしたい場合はどうすればよいでしょうか。
マルチパート メッセージをpostMessage
ハンドラーに渡すには、いくつかの方法があります。最初の (そして「クリーン」ではない) 方法は、区切り文字を使用してから、文字列を介してデータを渡すことです。
ユーザー ID、アクション、およびユーザー名を渡したいとしましょう。文字列は次のようになります。
54|do_logout|chris
postMessage
ハンドラー内で、渡されたデータを文字にsplit
( docs ) する|
ことができ、メッセージの各セグメントを必要に応じて使用できます。
もう 1 つの方法は、文字列を手動で作成/分割する代わりに、JSON ( docs ) を使用して一方のオブジェクトを文字列に変換し、JSON を使用してハンドラー内のオブジェクトに変換することです。
var pass_data = {
'name':'Chris',
'id':54,
'action':'do_logout'
};
target_window.postMessage(JSON.stringify(pass_data), "http://www.example.net");
...次にハンドラーで:
function (event) {
var pass_data = JSON.parse(event.data);
}
JSON
ただし、すべてのユーザー エージェント、特に古いユーザー エージェントでオブジェクトが提供されているわけではないため、必ずテストしてください。JSON のサポートを調整するためのサードパーティ ライブラリが多数 (非常に多く) 存在するため、完全に採用されていないからと言って怖がってはいけません。
そのオブジェクトをすぐに渡すことができればもっといいと思いませんか? さて、Firefox 6 ( source ) を見ると、postmessage ハンドラに渡すデータはオブジェクトかもしれません。オブジェクトはシリアル化されるため、その面でいくつかの懸念がありますが、次のとおりです。
var pass_data = {
'name':'Chris',
'id':54,
'action':'do_logout'
};
target_window.postMessage(pass_data, "http://www.example.net");
もう少しいいですよね?残念ながら、現在のバージョンの IE では文字列しか処理できません。IE 10に関する将来の計画に関する議論を見つけることができませんでしたpostMessage
。さらに、IE 8/9 にはpostMessage
、フレーム以外で壊れる既知のバグがあります。(ソース)。
あなたの質問の特定の側面 - コールバック - に入ります。関数名でコールバックを渡すことができない限り、関数を渡す方法はありません。匿名関数はありません。これは、データが実際にハンドラーに渡される方法に関連しています。実際には、データとしてのオブジェクトのサポートは「ありません」。舞台裏で、ブラウザーは渡されたオブジェクトを文字列に変換します (シリアル化)。
stringify
そうは言っても、オブジェクトを渡すことは、渡す前にオブジェクトにJSON を使用することとまったく同じであることを理解する必要があります。シリアライズ/アンシリアライズはあなた次第です。
ここでのポイントは次のとおりです。
ドキュメントとリファレンス
window.postMessage
: https://developer.mozilla.org/en/DOM/window.postMessageString.split
: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/splitJSON.stringify
: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/JSON/stringifyJSON.parse
: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/JSON/parsenpm で見つけた "silver-bullet"という素敵なプラグインがあります。コールバックで postMessage を実行し、eventEmitter を使用して特定のイベントも取得します。それは非常にうれしいです。
しかし、これを実装するには、次のようにします...
phostMessage(iframe, someObj, callback);
これを行う必要があります:
これは、その非常に基本的なデモンストレーションです。
var callbacks = {};
// when receiving messages
window.addEventListener('message', function(ev) {
// todo: add origin check
if (!ev.data)
return;
var message;
try {
message = JSON.parse(ev.data);
} catch (ex) {
console.error(ex);
}
// ignore messages not having a callback ID
if (!message || !message.callbackId)
return;
// we are the sender getting the callback
if (callbacks[message.callbackId]) {
callbacks[message.callbackId](message);
delete callbacks[message.callbackId];
return;
}
// we are the receiver so we respond with the callback ID
// todo: restrict who can receive message (last param)
iframe.contentWindow.postMessage(JSON.stringify(message), '*');
});
// when sending messages
function phostMessage(iframe, obj, callback) {
obj.eventId = Math.random();
callbacks[obj.eventId] = callback;
// todo: restrict who can receive message (last param)
iframe.contentWindow.postMessage(JSON.stringify(obj), '*');
}
この概念をもう少し進めて、メッセージを呼び出して渡す目的のハンドラー関数名がメッセージに含まれるメッセージ ハンドラー ルックアップを使用します。メッセージ ハンドラーは、完了時にコールバックを起動するコールバックも受け取ります。コールバックには、受信したコールバック ID を送り返すネイティブ ポスト メッセージを再度呼び出すという単純なロジックがあります。
したがって、メッセージ イベント処理のコードの最後の行は次のようになります。
if (messageHandler[message.handler])
messageHandler[message.handler](message, function() {
iframe.contentWindow.postMessage(JSON.stringify(message), '*');
});
else
iframe.contentWindow.postMessage(JSON.stringify(message), '*');
これにより、非同期処理が可能になります。
実際のコードを渡さずにコールバックをトリガーする非常に簡単な方法は次のとおりです。
目標
var callbacks = {
myCallback: function() { doSomething(); }
};
window.addEventListener('message', function (ev) {
// origin checking etc
callbacks[ev.data]();
}, false);
ソース
target.postMessage('myCallback', 'http://www.example.com');