以下斜め読んだ内容

pseudo translation of useful posts, book reviews, remarks,etc. twitter: feeddict

Nicholas C. Zakas「getElementsByTagName()がquerySelectorAll()よりも高速な件」

NCZOnline 2010.9.28のエントリ

Why is getElementsByTagName() faster that querySelectorAll()?

  • querySelectorAll()で取得されるNodeListは更新されない(static)件について
  • getElementsByTagName()と比較して
  • 処理の重さや、重くなる訳を仕様書やWebKitの実装を参照しながら説明して
  • この2つのメソッドの使いどころを手短に記す

という主旨のエントリ

以下斜め読んだ内容
  • エントリ書いたきっかけ
    • Scott Schillerのツイート
      • ほぼ全てのブラウザで「getElementsByTagName("a")」が「querySelectorAll("a")」よりも高速、と
    • jsPerf上で比較テストある
    • 自分(Nicholas)とScottとRyan Grove(YUIチーム)でtwitter上で議論してみた
    • 議論したことのフィードバックがこのエントリ
  • querySelectorAll()/getElementsByTagName()の違い
    • 引数(タグ名か/CSSセレクタか)が違う
    • 戻り値はともにNodeListsだけど、querySelectorAll()は静的、getElementsByTagName()は動的
  • 動的な(live)NodeLists
    • DOMの不思議なところの1つ
    • DOM Level 3 specに定義されてる
    • HTML文書だとNodeLists=HTMLCollection
    • 仕様書の該当箇所曰く
      • NodeList(or NamedNodeMap)オブジェクトは動的(Live)
        • DOMツリーに変更が入り、取得したNodeListに影響のある部分であれば、取得されたNodeListも変更される
    • getElementsByTagName()は動的なNodeListsを返す
    • liveなNodeListは使われてる
  • 静的な(static)NodeLists
    • 静的なNodeList取得
    • 仕様書の該当箇所(Selectors API spec)曰く
      • querySelectorAll()の戻り値は静的でないといけない
      • DOMツリーへ加えられた変更は、querySelectorAll()使って取得されたNodeListへ反映させててはならない
      • 取得時点でのNodeLists
//getElementsByTagName()例
//divs.lengthが増え続けるので、無限ループになる
var divs = document.getElementsByTagName("div"),
    i=0;

while(i < divs.length){
    document.body.appendChild(document.createElement("div"));
    i++;
}
//querySelectorAll()例
//DOMツリー内のdiv要素の数が増えていくが
//divs.lengthの数は変わらないので、ループは止まる
var divs = document.querySelectorAll("div"),
    i=0;

while(i < divs.length){
    document.body.appendChild(document.createElement("div"));
    i++;
}
  • querySelectorAll()が(getElementsByTagName()より)速いわけ
    • WebKitソースコードを見ながら説明
    • 動的なNodeList
      • 取得時点で対象となる要素すべてを走査していない
      • 新規インスタンス作成時はキャッシュにオブジェクトを作成するだけ
        • DynamicNodeList.cppの48行目以降
        • オーバーヘッドはとても少ない。
      • 生成済み動的なNodeListへアクセスするときは、document全体の変更点を問い合わせる
        • lengthプロパティ(DynamicNodeList.cppの57行目以降)やitem()メソッド(DynamicNodeList.cppの109行目以降)の戻り値でわかる
    • 静的なNodeList
      • 取得時点でのスナップショットを作成しないといけないので、対象要素すべてを走査する必要あり
      • 新規インスタンス作成時は、別ファイルにオブジェクトを作って、ドキュメント内のマッチする要素を全部チェックしてリスト作成する
      • SelectorNodeList.cppの61行目以降にループ使って引数にマッチする要素をループ使ってチェックしてるのがわかる
  • 使い分け
    • getElementsByTagName()
      • スナップショットが不要のとき
    • querySelectorAll()
      • 複雑なcssセレクタ使ってNodeList取得してるとき
      • スナップショットが必要なとき
  • コメント欄

あとでかく