15

ベンチマークはQSA & を比較.forEachしますNodeIterator

toArray(document.querySelectorAll("div > a.klass")).forEach(function (node) {
  // do something with node
});

var filter = {
    acceptNode: function (node) {
        var condition = node.parentNode.tagName === "DIV" &&
            node.classList.contains("klass") &&
            node.tagName === "A";

        return condition ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT
    }  
}
// FIREFOX Y U SUCK
var iter = document.createNodeIterator(document, NodeFilter.SHOW_ELEMENT, filter, false);
var node;
while (node = iter.nextNode()) {
    // do thing with node    
}

今はどちらかNodeIteratorが悪いか、間違っています。

質問:いつ使用する必要がありNodeIteratorますか?

ご存じないかもしれませんが、DOM4 は NodeIterator が何であるかを指定しています

4

2 に答える 2

14

さまざまな理由で遅いです。最も明白なのは、誰もそれを使用していないという事実であり、それを最適化するために費やされた時間がはるかに少ないということです。もう1つの問題は、大量の再入可能であり、すべてのノードがJSを呼び出して、フィルター関数を実行する必要があることです。

ベンチマークのリビジョン3を見ると、イテレーターが使用getElementsByTagName("*")して実行していることの再実装を追加し、その上で同じフィルターを実行していることがわかります。結果が示すように、それは非常に高速です。JS-> C++->JSへの移行は遅いです。

JS(getElementsByTagNameケース)またはC ++(ケース)でノードを完全にフィルタリングするquerySelectorAll方が、境界を繰り返し越えてフィルタリングするよりもはるかに高速です。

で使用されるセレクターマッチングもquerySelectorAll比較的スマートです。右から左へのマッチングを行い、事前に計算されたキャッシュに基づいています(ほとんどのブラウザーは、クラス「klass」を持つすべての要素のキャッシュリストを反復処理します。これはa要素であり、親がdiv)であるかどうかを確認します。したがって、ドキュメント全体を反復処理する必要はありません。

それを考えると、NodeIteratorをいつ使用するのですか?基本的に、少なくともJavaScriptでは決してありません。Javaなどの言語(間違いなくNodeIteratorと呼ばれるインターフェースがある主な理由)では、フィルターがフィルターと同じ言語になるため、他の言語と同じくらい高速になる可能性があります。それとは別に、それが理にかなっているのは、Nodeオブジェクトを作成するためのメモリ使用量がNodeの内部表現よりもはるかに多い言語でのみです。

于 2011-10-30T14:14:48.917 に答える