20

これまでのところ、1 つのウィンドウが 1 種類のメッセージを送信し、もう 1 つのウィンドウがメッセージを 1 つの方法で解釈する postmessage のチュートリアルしか見ていません。

ウィンドウ間でさまざまな種類の対話を行いたい場合、postmessage でそれを処理できますか?

それは、postmessage がすべきことの粒度に反しているのでしょうか?

たとえば、カスタム コールバックを送受信できるようにしたい場合はどうすればよいでしょうか。

4

4 に答える 4

62

マルチパート メッセージを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 を使用することとまったく同じであることを理解する必要があります。シリアライズ/アンシリアライズはあなた次第です。

ここでのポイントは次のとおりです。

  • postMessage のクロスブラウザー サポートはまだ制限されています
  • 標準準拠のブラウザの新しいバージョンでは、文字列に加えてオブジェクトの通過を許可する傾向があります
  • 渡されたオブジェクトはシリアル化されるため、関数参照は許可されません
  • 「実際に」最も広くサポートされているのは文字列のみのデータです。つまり、さまざまなユーザー エージェントをサポートしたい場合は、上記のように文字列に固執し、データを「パック」する必要があります。
  • Internet Explorer は、これまでに作成したすべての計画 (家族旅行を含む) を台無しにします。

ドキュメントとリファレンス

于 2011-12-12T20:00:47.647 に答える
4

postMessage によるコールバック: 非常に可能性が高く、非常に便利

npm で見つけた "silver-bullet"という素敵なプラグインがあります。コールバックで postMessage を実行し、eventEmitter を使用して特定のイベントも取得します。それは非常にうれしいです。

しかし、これを実装するには、次のようにします...

phostMessage(iframe, someObj, callback);

これを行う必要があります:

  1. 通信するフレーム間で渡される共通のコールバック IDが必要です。
  2. 送信者は、メッセージごとに一意のコールバック ID を作成し、それをコールバック ルックアップ ハッシュに格納して、送信後にコールバックを見つけます。
  3. メッセージの受信者は、コールバック ID が送り返されることのみを保証します。
  4. 通信するすべてのフレームは、これに同じ JS ライブラリを使用します。

これは、その非常に基本的なデモンストレーションです。

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), '*');

これにより、非同期処理が可能になります。

于 2015-06-25T16:01:45.087 に答える
0

実際のコードを渡さずにコールバックをトリガーする非常に簡単な方法は次のとおりです。

目標

var callbacks = {
  myCallback: function() { doSomething(); }
};
window.addEventListener('message', function (ev) {
  // origin checking etc
  callbacks[ev.data]();
}, false);

ソース

target.postMessage('myCallback', 'http://www.example.com');
于 2012-08-03T20:03:18.157 に答える