Hatena::Groupjavascript

JavaScriptで遊ぶよ

 | 

2010-02-27

非同期パフォーマンス

13:52

色んな方法の非同期的実行で、どれが速いか (呼び出しまでの時間が短いか) を調べてみた。

テスト。

結果。

Chromium Safari Firefox Opera 10.10 Opera 10.50
setTimeout 4.32ms 10.201ms 10.302ms 10.38ms 9.876ms
img.onerror 0.199ms 0.678ms 0.201ms 0.058ms 0.575ms
script.onreadystatechangefailfail fail fail fail
script.onload0.414ms 0.138ms 0.414ms fail fail
xhr.onreadystatechangefail0.622ms fail 0.078ms 0.079ms
self.postMessage0.096ms 0.123ms 0.112ms 0.049ms 0.094ms

Safari は script.onload が速いな。Chromium と Firefox では img.onerror が速い。

Opera 10.10 の img.onerror (JSDeferred のやってる方法) で異常に速いのは、途中で描画が入らないためなんだけど、Opera 10.50 からは描画が入るようになってる。xhr.onreadystatechange でも同じような感じなんだと思う。

あと iframe.onload とかもやってみたけど、setTimeout より時間かかってた。40ms ぐらいだったかな。openDatabase して transaction というのはもっと遅かった。

他に非同期 API ってあったっけ?

self.postMessage を追加。めっちゃ速い。window.addEventListener('message') では全部の message イベントを捕まえてしまうので、同一性担保のためにカウントをインクリメントさせて投げてるんだけど、いつか限界に逹っすることを考えると Math.random() のほうがいいのかな。Math.random() のほうが0.01msぐらい遅くなる。

続きを書いた。


setTimeout
function async(callback) {
  setTimeout(callback, 0);
}
img.onerror (data:uri)
function async(callback) {
  var img = new Image;
  img.addEventListener('error', callback, false);
  img.src = 'data:,foo';
}
script.onreadystatechange
function async(callback) {
  var script = document.createElement("script");
  script.type = "text/javascript";
  script.src  = "javascript:";
  script.onreadystatechange = function () {
    document.body.removeChild(script);
    callback();
  }
  document.body.appendChild(script);
}
script.onload (data:uri)
function async(callback) {
  var script = document.createElement('script');
  script.onload = function() {
    document.body.removeChild(script);
    callback();
  }
  script.src = 'data:text/javascript,';
  document.body.appendChild(script);
}
xhr.onreadystatechange (data:text/plain,foo)
function async(callback) {
  var xhr = new XMLHttpRequest;
  xhr.open('GET','data:text/plain,foo',true);
  xhr.onreadystatechange = function() {
    xhr.onreadystatechange = null;
    callback();
  };
  xhr.send(null);
}
self.postMessage
function async(callback) {
  var n = ++async.count;
  window.addEventListener('message',function(e){
    if (e.data == n) {
      window.removeEventListener('message', arguments.callee,false);
      callback();
    }
  },false);
  window.postMessage(n, location.protocol + "//" + location.host);
}
async.count = 0;

os0xos0x2010/02/27 16:46postMessage試してみました。Chrome、Firefox、Operaでなかなか良好です。
http://ss-o.net/test/Async_test.html
IE8でも動くようにしたんですが、なんと完全に同期的に動くらしくて、すぐにStack overflowに…。
postMessageは http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2008-April/014551.html あたりで非同期になったみたいなので、IEの実装が古いみたいです…。
ちなみに、iframeを静的に置いているのはIE用で、それ以外のブラウザは動的に作ったabout:blankなフレームでいけるみたいです。

edvakfedvakf2010/02/27 17:27いい感じですね。
Chrome 0.164ms
Safari 0.23ms
Firefox 0.25ms
Opera 0.197ms

postMessage は親ウィンドウが window.onmessage で受け取らないといけないのが難点ですよね。
Deferred.parallel っぽいことができないのが痛い。(MessageChannel があれば別だけど)

postMessage が昔は同期だったのがびっくり。2008年4月ってことは Google Chrome が出るより前か。
今やマルチプロセスブラウザの方向に向かってるからって cookie まで非同期にしようというところなのに。
http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2010-February/025300.html

about:blank な iframe と言えば、たしか最近 about:blank な iframe は同期的であることが確認されたっぽいです。(ちゃんと読んでないですが)
http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2010-January/024747.html
iframe.src = 'about:blank'; document.body.appendChild(iframe); iframe.contentDocument.write()
とできるんだから当然なのかな。

os0xos0x2010/02/28 12:20そうだ、そもそもIE無視すれば、自分自身にpostMessageするだけでいけるんでした。iframeがなくなってすっきり。
http://ss-o.net/test/Async_test2.html
IE以外の最新ブラウザと限定すれば、これがベターな感じですね。

edvakfedvakf2010/02/28 12:40Chrome 0.097ms
Safari 0.125ms
Firefox 0.119ms
Opera 0.043ms

おおー。かなりいい感じです。表に追加しときますね。

os0xos0x2010/02/28 13:33なんどもすみません、本当はこういう風に自分でイベント作って投げて捕まえてとできれば良かったんですが、
http://ss-o.net/test/Async_test3.html
これだと非同期にならないんですよね…。全部自分でやってるから当然のような気もしますが。
まあ、test2のほうでも、message dataのところでユニークにすれば、Deferred.parallel 的なこともできるから、とりあえずはOKですかね。

edvakfedvakf2010/03/02 05:51http://dev.opera.com/articles/view/timing-and-synchronization-in-javascript/
に書いてありました。

There is a special case where events are not sequenced, but nested. If an event if fired explicitly through script using the dispatchEvent()-method (fireEvent() in Internet Explorer), the event is dispatched immediately. The initial script will only continue when the dispatched event has finished (and the default action has executed).

今読んでもすばらしいドキュメントですね。

 |