web-dev-qa-db-ja.com

複数の関数またはカスタムコールバックを含むPostMessage

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

ウィンドウ間でさまざまな種類のインタラクションが必要な場合、ポストメッセージでそれを処理できますか?

それは、ポストメッセージが行うことになっていることの粒子に反していますか?

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

19
johnnietheblack

マルチパートメッセージをpostMessageハンドラーに渡す方法はいくつかあります。 1つ目(そして「クリーン」ではない方法)は、区切り文字を使用してから、データをストリングで渡す方法です。

ユーザーID、アクション、およびユーザー名を渡したいとしましょう。文字列は次のようになります。

54|do_logout|chris

postMessageハンドラー内で、渡されるデータは|文字のsplitdocs )にすることができ、メッセージの各セグメントを必要に応じて使用できます。

文字列を手動で作成/分割する代わりに、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サポートをシムするためのサードパーティライブラリはたくさんありますので、完全に採用されていないことを恐れないでください。JSONは間違いなく安全な「前進」標準です。

そのオブジェクトをすぐに渡すことができればもっといいのではないでしょうか。さて、Firefox 6( source )を見つめていると、ポストメッセージハンドラーに渡すデータはオブジェクトである可能性があります。オブジェクトはシリアル化されるため、その面でいくつかの懸念がありますが、次のようになります。

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は、これまでに作成したすべての計画を台無しにします(家族の休日を含む)

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

54
Chris Baker

PostMessageによるコールバック:非常に可能で非常に便利

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

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

phostMessage(iframe, someObj, callback);

あなたはこれをしなければなりません:

  1. 通信するフレーム間で渡される共通コールバックIDが必要です。
  2. 送信者は、各メッセージに一意のコールバックIDを作成し、それをコールバックルックアップハッシュに格納して、送信後にコールバックを検索します。
  3. メッセージのreceiverは、コールバック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), '*');

これにより、非同期のものが発生します。

3
Jason Sebring

私は最近同じ問題に直面しました。何時間も検索した後、私は post-robot に出くわしました。これはPaypalによって開発され、postMessageのコールバックを含む私の問題のほとんどを解決しました。

また、ペイロード内での関数の受け渡しもサポートしています。

ここで紹介をチェックできます ポストロボットの紹介

0
Atishay Jain

実際のコードを渡さずにtriggerコールバックを行う簡単な方法は次のとおりです。

ターゲット

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

ソース

target.postMessage('myCallback', 'http://www.example.com');
0
Jacob Rask