Hatena::ブログ(Diary)

latest log このページをアンテナに追加 RSSフィード

2008-10-05

JavaScript の高速化その2 「全てを疑い、自分の目で確認すること」

こういう泥臭い資料作りもやってるので、一応書き残します。

問題1. array.length へのアクセス

var ary = new Array(100000); な配列があるとします。

IE6環境下で、配列の長さを求める方法を、早い順に並べてください。

TEST1. a.length;

TEST2. var L = "length"; a[L];

TEST3. a["length]";

正解は、TEST1 < TEST3 < TEST2 です。

BrowserTEST1TEST2TEST3総評
Chrome111全て同じスコア
Safari123TEST2はTEST1の2倍, TEST3に至っては3.4倍スコアが違う
Opera9.27111全て同じスコア
Opera9.6β1221.3倍スコアが違う
Firefox2121TEST1とTEST2で1.5倍違う
Firefox3212TEST2が12%早い
IE6132
IE8β2121TEST1とTEST2で1.2倍違う

数値は順位


配列の要素数が欲しければ、 a.length を使いましょう。

問題2. document.getElementById() へのアクセス

<div id="root"></div>

IE6環境下で、この要素を検索する方法を、早い順に並べてください。

TEST10. document.getElementById("root");

TEST11. var ID = "getElementById"; document[ID]("root");

TEST12. var _doc = document; _doc.getElementById("root");

TEST13. var _doc = document, ID = "getElementById"; _doc[ID]("root");

正解は、TEST12 < TEST13 < TEST10 < TEST11 です。TEST12とTEST13の差は0.0058%0.58%です。

TEST12とTEST11では5.6%の差が見られます。

BrowserTEST10TEST11TEST12TEST13総評
Chrome3312微妙にTEST12が早い
Safari2413TEST10とTEST11では2倍スコアが違う
Opera9.273411TEST12とTEST11では2倍スコアが違う
Opera9.6β3412TEST12とTEST11では1.8倍スコアが違う
Firefox23412TEST11とTEST12では1.3倍スコアが違う
Firefox32413TEST11とTEST12では2.1倍スコアが違う
IE63412
IE8β24412TEST11とTEST12では1.6倍スコアが違う

数値は順位

idで要素を検索したければ、var _doc = document; _doc.getElementById("root"); を使いましょう。

問題3. ネストされたプロパティへのアクセス

これと
  function hoge() {
    var ary = Array(10000);
    return Array.prototype.slice.call(ary);
  }
これでは?
  function hoge() {
    var ary = Array(10000), slice = Array.prototype.slice;
    return slice.call(ary);
  }

IE6では後者が7%ほど早くなります。Chromeでも1%ほど高速化されます。

結論

lengthプロパティにアクセスする場合は、小細工はしないほうが良く、

ネストされたプロパティにアクセスする場合は、ネストを浅くするためにキャッシュしておいたほうが良く、

documentにアクセスする場合には、documentをローカル変数キャッシュしたほうが速度が向上します(ローカルスコープの中にですよ)。

つまり

var _doc = document; // これだと、いまいち効果が薄いので、
function hoge() {
  var e = _doc.getElementById("piyo");
}
function hoge() {
  var _doc = document; // 面倒でもローカルスコープ内で宣言する必要がある。
  var e = _doc.getElementById("piyo");
}

プロパティによっては特別扱いされているものもあるかもしれませんが、原則こんな感じでいけます。

ほかには、

var i = 0, sz = elm.childNodes.length;
for (; i < sz; ++i) { elm.childNodes[i] }

よりも

var c = elm.firstChild;
for (; c; c = c.nextSibling) { c }

が、60倍以上高速だったりします(in IE6)。

あとは、Papervision3DJavaScriptに移植しようとたくらみ、コードリードしていた時に、こんな感じの(関数引数をわざわざローカル変数にマップしている)コードを沢山見かけました。

function(aa, bb, cc) {
  var a = aa, b = bb, c = cc;
  return a * b * c;
}

高速化目的なのかな? と思い同様のコードをJavaScriptで試してみたら、いずれのブラウザでも期待を裏切る結果になりました。

もしかして、上記の書き方をすると、ActionScript では高速化するのかもしれません。


興味がある方はいろいろと計測してみると良いでしょう。

# 良かったら結果も教えてください。

id:amachang が以前 http://d.hatena.ne.jp/amachang/20071010/1192012056IE + document について言及していましたが、他のブラウザでも通用する手法のようです。


トレードオフ

やればやるほど「あのコードはちょっと…」「なんかスッと入ってこない」といわれる要因になる危険性があることも自覚しつつ、これらの結果を踏まえ uupaa.js をちょっと書き直します。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト

コメントを書くには、なぞなぞ認証に回答する必要があります。