2

重複の可能性:
コンテキストを使用した jQuery セレクターのパフォーマンス

jQuery DOCSでは、それは言う

デフォルトでは、セレクターはドキュメント ルートから始まる DOM 内で検索を実行します。ただし、$() 関数のオプションの 2 番目のパラメーターを使用して、検索用の代替コンテキストを指定できます。

私の理解に基づいてcontext、2番目のパラメーターとして渡されたものを使用した選択は、渡されたものを使用しない同じ選択よりも高速である必要がありますcontext。ただし、いくつかのテストを実行しましたが、そうではないか、少なくともそうではないようですいつもそうではありません。

$("div1, #div2")詳しく説明すると、最初は、複数の要素を一度に検索する ( ) 方が、2 つの要素を個別に検索する ( ) よりも速いかどうかを確認したかったの$("#div1") $("div2")です。context次に、 を使用した場合と使用しない場合でテストして、を使用しcontextた場合のcontext速度を確認することにしました。

たとえば、次の基本的な HTML マークアップがあるとします。

<div id="testCnt">
    <div id="Div0"></div>
    <div id="Div1"></div>
    <div id="Div2"></div>
    <div id="Div3"></div>
    <div id="Div4"></div>
    <div id="Div5"></div>
    <div id="Div6"></div>
    <div id="Div7"></div>
    <div id="Div8"></div>
    <div id="Div9"></div>
</div>

そして、次の JavaScript (jQuery 1.8.2、および FireBug を使用してテスト済み)

$(function () {    
    var $dvCnt = $('#testCnt');
    var dvCnt = $dvCnt[0];

    console.time('Individual without cache');
    for (var i = 0; i < 10000; i++) {
        $('#Div0').text('Test');
        $('#Div1').text('Test');
        $('#Div2').text('Test');
        $('#Div3').text('Test');
        $('#Div4').text('Test');
        $('#Div5').text('Test');
        $('#Div6').text('Test');
        $('#Div7').text('Test');
        $('#Div8').text('Test');
        $('#Div9').text('Test');

    }
    console.timeEnd('Individual without cache');

    console.time('Individual with $cache');
    for (var i = 0; i < 10000; i++) {
        $('#Div0', $dvCnt).text('Test');
        $('#Div1', $dvCnt).text('Test');
        $('#Div2', $dvCnt).text('Test');
        $('#Div3', $dvCnt).text('Test');
        $('#Div4', $dvCnt).text('Test');
        $('#Div5', $dvCnt).text('Test');
        $('#Div6', $dvCnt).text('Test');
        $('#Div7', $dvCnt).text('Test');
        $('#Div8', $dvCnt).text('Test');
        $('#Div9', $dvCnt).text('Test');

    }
    console.timeEnd('Individual with $cache');

    console.time('Individual with DOM cache');
    for (var i = 0; i < 10000; i++) {
        $('#Div0', dvCnt).text('Test');
        $('#Div1', dvCnt).text('Test');
        $('#Div2', dvCnt).text('Test');
        $('#Div3', dvCnt).text('Test');
        $('#Div4', dvCnt).text('Test');
        $('#Div5', dvCnt).text('Test');
        $('#Div6', dvCnt).text('Test');
        $('#Div7', dvCnt).text('Test');
        $('#Div8', dvCnt).text('Test');
        $('#Div9', dvCnt).text('Test');

    }
    console.timeEnd('Individual with DOM cache');


    console.time('Multiple without cache');
    for (var i = 0; i < 10000; i++) {
        $('#Div0,#Div1 ,#Div2 ,#Div3 ,#Div4 ,#Div5 ,#Div6, #Div7, #Div8, #Div9').text('Test');
    }
    console.timeEnd('Multiple without cache');

    console.time('Multiple with $cache');
    for (var i = 0; i < 10000; i++) {
        $('#Div0,#Div1 ,#Div2 ,#Div3 ,#Div4 ,#Div5 ,#Div6, #Div7, #Div8, #Div9', $dvCnt).text('Test');
    }
    console.timeEnd('Multiple with $cache');

    console.time('Multiple with DOM cache');
    for (var i = 0; i < 10000; i++) {
        $('#Div0,#Div1 ,#Div2 ,#Div3 ,#Div4 ,#Div5 ,#Div6, #Div7, #Div8, #Div9', dvCnt).text('Test');
    }
    console.timeEnd('Multiple with DOM cache');
});

ここにjsbinがあります

次のような結果が得られます

キャッシュなしの
個体: 11490ms $cache のある
個体: 13315ms DOM キャッシュのある個体: 14487ms

キャッシュなしの
複数: 7557ms $cache を使用した
複数: 7824ms DOM キャッシュを使用した複数: 8589ms

誰かが何が起こっているのかについて洞察を与えることができますか? 具体的には、jQuery コンテキストが渡されたときに検索が遅くなるのはなぜですか?

編集:

ここのアンサーのほとんど (およびcontext を使用した jQuery セレクターのパフォーマンス) は、基本的に、この例の DOM が小さすぎて実際に多くを得ることができないか、選択IDが高速になると言っています。私は両方の点を理解しています。私の質問の主なポイントは、なぜ検索がcontext 遅くDOMなるのかということです。

@pebbleが遅い理由は、jQuery がネイティブ ブラウザー メソッドを使用できないためであると示唆しました ( getElementByID)。

とにかく、クラスごとに検索するケースを追加してjsPerfにテストをダンプしましたが、今回もキャッシュを使用した複数のクラスの検索が最も高速であることに再び驚きました。

4

4 に答える 4

2

コンテキストを使用すると速度が低下する状況がたくさんあると思います。これは主に、jQuery が dom 全体をトラバースするのではなく、可能な場合はブラウザのネイティブ メソッドを使用しようとするためです。この一例はdocument.getElementById、あなたの例のように使用することです。

なぜ減速するのですか?

getElementByIdドキュメント オブジェクトにのみ存在します。コンテキスト要素でこれを使用する方法はありません。つまりelement.getElementById. したがって、私の理論では、jQuery は最初に を使用して id リクエストを実行しdocument.getElementById、次にコンテキスト セットがある場合は、各要素の親をスキャンして、それらのいずれかがコンテキストの子として存在するかどうかを確認し、それによってプロセスが遅くなるというものです。

遅い可能性のあるセレクターのその他の例

また、使用しているセレクターに応じて、パフォーマンスが向上する他の場所も見つけることができます。すべては、jQuery が作業を高速化するために使用できるメソッドにまで及びます。例えば:

$('.className');

getElementsByClassNameほとんどの場合、className で選択するために提供されるその他のネイティブ メソッドを使用することに変換されますが、次のようになります。

$('.className .anotherClassName');

これを使用することはできず(関係を考慮に入れる必要があるため) 、問題を解決するにはquerySelector (存在する場合)または純粋な JavaScript ロジックの混合物を使用する必要があります。

使用可能なネイティブ メソッドについて十分に理解しておくと、jQuery クエリを最適化するのに役立ちます。


最適化の方法

コンテキストを使用して最適化したい場合は、これを使用しない場合よりもクエリが高速になると思います。

$('div', context);

getElementsByTagNameが存在するからでしょう。黎明期からしばらくの間、純粋な JavaScript で DOM 要素上で直接使用できます。ただし、これを行う場合は、次のことを行う方が速い場合があります。

$().pushStack( context[0].getElementsByTagName('div') );

また

$( context[0].getElementsByTagName('div') );

主な理由は、jQuery 関数呼び出しを削減したためですが、これははるかに簡潔ではありません。一般的な JavaScript 環境の多くに関して注意すべきもう 1 つの点は、引数を指定せずに関数を呼び出す方が、引数を指定して呼び出すよりもはるかに高速であることです。

特定の jQuery セレクターを最適化するための比較的使用されていない方法は、jQuery 疑似セレクターを使用することです。これにより、SQL クエリでeq使用するのと同様の方法で高速化できます。LIMIT 0,1

$('h2 > a');

すべての H2 内をスキャンして A 要素を探しますが、H2 内に A タグが 1 つしか存在しないことが最初からわかっている場合は、次のようにすることができます。

$('h2 > a:eq(0)');

さらに、H2 が 1 つしか存在しないことがわかっている場合、ロジックは同じです。

$('h2:eq(0) > a:eq(0)');


$().pushStack と $().add の違い

Jasper のコメントに応えて、2 つの関数の違いを次に示します。

。追加:

function (a,b){var c=typeof a=="string"?p(a,b):p.makeArray(a&&a.nodeType?
[a]:a),d=p.merge(this.get(),c);return this.pushStack(bh(c[0])||bh(d[0])?
d:p.unique(d))}

.pushStack:

function (a,b,c){var d=p.merge(this.constructor(),a);return
d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector
+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")"),d}

主な違いは、その目的を達成するために.add()使用.pushStack()することです。追加により、jQuery オブジェクトでさえも、より多くのデータ型をサポートできます。一方.pushStack、DOM要素用にのみ設計されているため、使用している場合はより最適になります:)


ID で選択するより簡単な方法はありますか?

これは明らかですが、時々見逃されることがあるので、これをここに置くと思いました.idで要素を選択するより迅速な方法は、次のようにすることです:

$(document.getElementById('id'));

すべては、jQuery/Sizzle がネイティブ メソッドを凌駕する方法がないためです。また、jQuery/Sizzle 側での文字列解析を回避することも意味します。ただし、jQuery の対応物ほどきれいではなく、おそらくそれほど速度が向上することはありませんが、最適化として言及する価値があります。id を頻繁に使用する場合は、次のようにすることができます。

jQuery.byid = function(id){
  return jQuery(document.getElementById(id))
};

$.byid('elementid');

上記は前の例よりも少し遅くなりますが、それでも jQuery よりも優れているはずです。

于 2012-10-24T21:14:44.140 に答える
1

ID で選択しているため、jQuery (またはシズル、忘れてしまいました) は、この場合、より高速な document.getElementById() にスキップしています。クラスを使用すると異なる結果が得られる場合がありますが、それでもブラウザーによって異なる場合があります。

http://jsperf.com/のようなものを使用して、テストを簡単にすることができます

于 2012-10-24T21:14:35.153 に答える
0

#elementid 属性を使用してテストを実行しているようです。

HTML ページのIDは一意である必要があることに注意してください。したがって、ID を検索するときにコンテキストを指定するかどうかにかかわらず、これは違いはありません。

クラスまたは要素タグ自体で要素をターゲットにしようとしている場合、このテストはより理にかなっている可能性があります。

$('.mydiv' , $('#innerDiv'))よりも速いかもしれません $('.mydiv')

于 2012-10-24T21:18:40.873 に答える
0

ID はブラウザーで高度に最適化されているため、ID を使用する場合、コンテキストのメリットはありません。

ID を使用すると、声をかけて「ねえ」と言うことができます。プログラミング以外の例として、あなたは人の部屋にいて、名前を叫ぶと、その人が答えます。

次に、コンテキストを見てみましょう。名前が男性の名前だとわかっているので、部屋を男性と女性に分けます。男性のグループに名前を尋ねるよりも。かなり簡単なもののための 1 つの余分なステップ。

属性などの特定のものを検索する場合に役立ちます。ブラウザが検索するのが難しく、高度に最適化されていないもの。特定の属性を持つ入力を探しているとします。ページ上のすべての入力を検索する必要がないように、それを含むことがわかっている要素を参照することをお勧めします。

ここで面白いのは、コンテキスト セレクターが遅くなることです。検索を使用することをお勧めします。なんで?複数の jQuery オブジェクトの作成を処理する必要があります。:)

だから代わりに

    $('.myClass', dvCnt).text('Test');

行う

    $(dvCnt).find('.myClass').text('Test');

複数のルックアップを行っている場合は、最初のルックアップを変数に格納することをお勧めします

    var myDiv = $(dvCnt)
    myDiv.find('.myClass1').text('Test');
    myDiv.find('.myClass2').text('Test');

しかし、jQuery が querySelector に対して実行するようになったので、querySelector がサポートしていない作成された jQuery セレクターを使用していない限り、これらの最適化はより小さなものになります。querySelector をサポートしていないブラウザでは、コンテキストが重要です。

于 2012-10-24T21:37:23.220 に答える