Hatena::Groupjavascript

JavaScriptで遊ぶよ

 | 

2010-02-28

Deferred.next_faster_way_postMessageを作ってみた

05:16

の続き。

JSDeferred の next を img.onerror よりさらに速くするために postMessage が使えるとわかったので、早速書いてみた。

Deferred.next_faster_way_postMessage = function(fun) {
  var d = new Deferred();
  var id = + new Date() + Math.random() + '';
  var handler = function (e) {
    if (e.data === id) {
      d.canceller();
      d.call()
    }
  };
  d.canceller = function () {
    window.removeEventListener('message', handler, false);
  }
  window.addEventListener('message', handler, false);
  window.postMessage(id, location.protocol + "//" + location.host);
  if (fun) d.callback.ok = fun;
  return d;
};

テストページ。

問題は、速すぎて Opera ではまったく動いてるところが見えなくて、Chromium と Safari でもほとんどのコマが飛んで見えること。

Deferred.next_faster_way_postMessage_help_redraw というやつでは Deferred.next_faster_way_readystatechange のように、一定時間以上立ったら setTimeout に切り替えるようになっているのだけど、Opera とか Chromium ではこれでも速すぎて、Firefox ではこれだと setTimeout が呼ばれすぎて意味ない。そもそも Firefox ではちゃんと描画されるので help_redraw な処理を入れる必要は無いのだけど。


擁護しておくと、JSDeferred の next でアニメーションするなんてことは普通はありえないので、気にするところはそこではないとも言える。アニメーションするなら 50ms とかでタイムアウトするはずだから。


安全にしてみた

コメント欄の指摘を受けて、iframe.contentWindow.addEventListener('message') を使うようにしてみた。

テストページで試せる。

Deferred.next_faster_way_postMessage2 = (function() {
  var iframe = document.createElement('iframe');
  iframe.style.display = 'none';
  document.body.appendChild(iframe);
  var win = iframe.contentWindow;

  return function(fun) {
    var d = new Deferred();
    var id = + new Date() + Math.random() + '';
    var handler = function (e) {
      if (e.data === id) {
        d.canceller();
        d.call()
      }
    };
    d.canceller = function () {
      win.removeEventListener('message', handler, false);
    }
    win.addEventListener('message', handler, false);
    win.postMessage(id, location.protocol + "//" + location.host);
    if (fun) d.callback.ok = fun;
    return d;
  }
}());

速度はほとんど変わらず。しかし DOM を弄るのはちょっと不本意。document.body 構築前かもしれないし。

でもこの方法だと Chromium + file: URL でセキュリティエラーになるのね…

os0xos0x2010/03/01 12:51問題は、すでにMessageEventが使われている/使うかもしれないところですね。
window.addEventListener('message', がいっぱいあったり、その中身次第では大惨事に…。
やはり、カスタムイベントが使えないのが痛いですね。
Namespace的なものをないみたいですし。

edvakfedvakf2010/03/01 12:55そういえばそうですね。JSON.stringify(e.data) 決め打ちしてたりしてエラーコンソールが大変なことになったり。
やっぱりあんまり良い方法ではないですね。

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