十三章第四回 Web Messaging 2
このページの最終更新日:
前回紹介したWeb Messagingには、まだ続きがあります。
それは、チャンネルメッセージングです。
これは何かというと、前回紹介したWeb Messagingにおいては、メッセージを送るpostMessageはwindowのメソッドであり、同じくメッセージを受けるのもwindowオブジェクトのmessageイベントです。
ここで、複数のウィンドウと同時に通信する場合を考えましょう。この場合、2つのウィンドウからくるメッセージが混在してしまい、判別する処理などが必要になり面倒です。
そこで、通信相手ごとに専用の回線を用意して、その中で通信することができます。これがチャンネルです。
MessageChannel
チャンネルを開設するには、MessageChannelというオブジェクトを用意します。このオブジェクトのインスタンスを作成すると、2つのMessagePortが作成され、port1とport2という2つのプロパティに入ります。
var channel=new MessageChannel();
channel.port1; //MessagePort
channel.port2; //MessagePort
MessagePortとは、チャンネルを通してメッセージを送るための窓口のようなものです。チャンネルメッセージングにおいては、windowオブジェクトではなくMessagePortにおいてmessageイベントが発生します。
また、MessagePortは、postMessageメソッドも持っています。ここまで見て分かる通り、MessagePortは2つ組になっています。同じMessageChannelから作られたMessagePortがペアになっています。実質、MessageChannelには、このペアになったMessagePortを作る以外の機能はありません。
すなわち、あるMessagePortでpostMessageメソッドを利用すると、それで発せられたメッセージはもう1つのMessagePortに届き、messageイベントが発生します。このようにしてチャンネルメッセージングが行われるのです。
MessagePort
それでは、MessagePortの使い方を見てみましょう。messageイベントが発生するので、その扱いかたは前回紹介した場合と同じです。
しかし、postMessageには少しだけ違いがあります。前回のwindow.postMessageの場合は、第1引数が送るデータで第2引数がオリジンでした。しかし、MessagePortにおいては第2引数のオリジンはありません。なぜなら、MessagePortを送った時点(後述)で相手が誰かはわかっているからです。ですから、引数ひとつでメッセージを送るだけという単純な形で利用可能です。
また、MessagePortは、startとcloseというメソッド(いずれも引数無し)を持ちます。実は、MessagePortを利用する際は、まずこのstartメソッドを呼び出しておかないとメッセージを受信してくれないのです。closeは反対に、受信を終了してそのポートを無効化するメソッドです。
以上を踏まえて、挙動を確かめるためのサンプルを用意しました。結果はconsole.logで表示されるのでコンソールを開きましょう。また、詳しくはソースを参照しましょう。
このサンプルで、port1のpostMessageで送ったメッセージはport2に届きます。逆も然りです。
MessagePortを渡す
さて、以上でMessagePortの挙動は理解できたと思います。しかし、このままでは使い物になりませんね。1つのページの中でいくら通信しても仕方ありません。これを有効に利用するには、前回同様異なるウィンドウの間で通信しないと意味がありません。
そのためには、MessagePortを作って他のウィンドウに渡せばいいのです。
この方法は、実は前回紹介したMessagePortを介さない通常のWeb Messagingです。つまり、まず普通のpostMessageでMessagePortを送ってやり、それを受け取った側は以後MessagePortを利用して個別のメッセージングをしようということです。
さて、postMessageでMessagePortを渡す方法ですが、じつは一筋縄ではいきません。普通に第1引数のメッセージで送ればいいように思いますが、前回「送ることが可能なもの」として紹介した中にMessagePortは含まれませんから、これでは送れません。
ここで、window.postMessageの第3引数が登場します。これは当然ながら省略可能であり、指定する場合は配列を渡します。配列であるという点に注意しましょう。
この配列の中にMessagePortを入れてやれば、向こうに届きます。受け取る側では、これはメッセージではありませんからイベントオブジェクトのdataプロパティには入っていません。window.postMessageの第3引数に渡されたものは、イベントオブジェクトのportsプロパティとして配列のまま届きます。このようにしてMessagePortを受け渡すことができました。
なぜMessagePortは第1引数で普通に受け渡せないかというと、第1引数のデータは全てクローン(コピー)して送られるのに対し、MessagePortではクローンではなく現物をそのまま送らなければならない、という理屈からだそうです。第3引数は、現物を送るための機能ということになっていますが、今はMessagePort専用です。第3引数に渡したオブジェクトは向こうに送られてしまったので、それ以降こちら側で使うことはできません。
以上を利用したサンプル2を用意しました。詳細はサンプル2のソースを参照してください。
これでWeb Messagingについては終わりです。他のオリジンのページと通信したいときに役に立つかもしれません。
最後に、前回window.openによって他のブラウジングコンテキストを知る方法を紹介しましたが、実はもうひとつ他のブラウジングコンテキストを手に入れる方法があります。それはiframe要素を用いる場合です。詳しいことは七章第一回を参照してください。