Hatena::Groupjavascript

JavaScriptで遊ぶよ

 | 

2010-01-09

MessageChannel

05:58

昨日 HTML5 から分離されて独立した仕様になった postMessage 関連について、MessageChannel というのは知らなかったので調べてみた。

Chromium や最新 WebKit では既に使えるもので、

var channel = new MessageChannel;
channel.port2.onmessage = function(e) {alert(e.data)};
channel.port1.postMessage('foo');

とやると port1 から port2 にメッセージを遅れる。


自分で自分にメッセージを送ってもしょうがないので、ポートのうちの一つを他のウィンドウに渡してしまう。

  • parent.html
<iframe src="child.html"></iframe>
<script>
  var port;
  window.onmessage = function(e) { // 最初は window.onmessage で受け取る
    console.log(e.data);
    port = e.ports[0]; // 子ウィンドウの port のクローンが送られる
    port.onmessage = function(e) { // 指定されたポートでメッセージを受け取る
      console.log(e.data);
      port.postMessage('received : ' + (+new Date)); // 返信
    }
  }
</script>

  • child.html
<script>
  var channel = new MessageChannel;
  var port = channel.port1; // チャンネルのポートのうち、一つは自分で使う
  window.parent.postMessage('start', [channel.port2], '*'); // もう一つは親に送る
  setInterval(function() {
    port.postMessage('sent : ' + (+new Date));
  }, 2000);
  port.onmessage = function(e) { // 親からの返信を受け取る
    console.log(e.data);
  }
</script>

コンソールを見るとこんな感じ。

f:id:edvakf:20100110054327p:image

(↑なんと、ぴったり2000ms 後!)

これの何がいいか。

window.onmessage でメッセージを待つ場合、どのウィンドウからメッセージが来たのかわからない。例えば URL の同じ iframe を10個用意して、10個の子ウィンドウからメッセージを待つ場合、window.onmessage でメッセージを受け取っても、どの子ウィンドウからのメッセージか分からない。

port を固定しまえばそんな苦労は無い。


ちなみに、targetWindow.postMessage は以下のどちらかの形で使う。ports を送る場合は第二引数に割り込むのがものすごく気持ち悪い。

targetWindow.postMessage(message, targetOrigin);
targetWindow.postMessage(message, ports, targetOrigin);

いつのまにか仕様が変わってて、ports が第二引数に割り込むのではなくて optional な第三引数になった。


ports を送る場合、port そのものが送られるわけではなく、相手ウィンドウにクローンされる。


MessageChannel の例は Web Workers の仕様にもちょこっと出ている。

トラックバック - http://javascript.g.hatena.ne.jp/edvakf/20100109
 |