3

シングル ページ アプリケーションを最適化する方法を検討しており、現在は jQuery セレクターに焦点を当てています。

私は JavaScript の専門家ではありませんが、dom を再クエリするのではなく、jquery セレクターの結果を変数に格納して再利用する方がはるかにパフォーマンスが高いことを理解しています。

したがって、たとえば、これの代わりに:

$("#myItem").doSomething();
$("#myItem").doSomethingElse();

これを行う方が理にかなっています:

var result = $("#myItem");
result.doSomething();
result.doSomethingElse();

また、必要なクエリの量を減らすために、既存の jQuery オブジェクトに接続された find() セレクターを使用すると、パフォーマンスが大幅に向上する可能性があることを理解しています。

$("#myItem").find(".highlighted");

アプリケーションで常に再利用する多くのセレクターを、ローカル変数だけでなく、おそらくどこかのハッシュまたは外部関数に格納する可能性を探ることに興味があります。これが最適かどうかはわかりませんが、これが受け取る反応に興味があります。

Underscore.js の memoize 関数を使用してこれを実行しようとしましたが (失敗しました)、期待どおりに動作しません。ただし、コンセプトは次のようになります。

   jquerySelect = function () {
                var elements = _.memoize(function (selection) {
                    return $(selection);
                });
                return elements;
            };

ここでの考え方は、「return $(selection)」の実際の結果作業が 1 回実行された後、結果がキャッシュされて返されるということです。

これを次の方法で使用できるようにしたいと思います。

utils.jquerySelect(".highlighted").find("span")

この単純な例では、キャッシュのキーは ".highlighted" であり、ユーティリティ関数は結果にアクセスする方法を知っているため、DOM を走査する作業が再度行われるのを防ぐことができます。「return」ステートメントが毎回ヒットするため、私の実装は現在機能しません。

このアプローチに欠陥があるかどうかはわかりませんが、そうかもしれません。ただし、これが機能する方法を見つけた場合、またはこれを行うより良い方法を見つけた場合はお知らせください。

4

5 に答える 5

3

これは悪い考えではありません。実際、JQuery用の同様のメモ化プラグインがすでに数十個あります。あなたのアプローチの主な課題は、メモ化された結果をいつ使用できるか、そしてDOMの変更のためにいつ無効になるかを知ることです。JQueryコードは、DOM内のノードを選択するのと同じように、ノードを追加、削除、および変更する可能性が高いため、メモ化されたキャッシュからセレクターをいつ無効にする必要があるかを知ることは重要な問題です。

メモ化プラグインがこれを回避する方法は、通常、$_()メモ化するセレクターやメモ化した結果を取得するセレクターなど、いくつかの代替構文を提供することです。ただし、これにより、セレクターに文字列/ハッシュルックアップが追加されます。それで、結局、ローカルでキャッシュすることに対するこれの本当の利点は何ですか?

一般的に言って、JQueryが本質的にどのようにDOMにモナディック変換を提供するDSLであるか(チェーンとも呼ばれます)についてもっと学ぶ方が良いでしょう。

たとえば、質問のコードは次のように記述できます。

$("#myItem").doSomething().doSomethingElse();

.end()チェーン内の結果はすでに内部でメモ化されているため、セレクタスタックをポップするために使用することもできます。

$("#myItem").doSomething().find('a').hide().end().doSomethingElse();
// a in #myItem are hidden, but doSomething() and doSomethingElse() happen to #myItem

また、ほとんどのJQuery選択のコストは過大評価される可能性があります。ID選択(で始まるセレクター)は、Sizzleエンジンの代わりにの#ような高速DOMメソッドに渡されます。document.getElementById単一のDOM要素に解決されるセレクターへの呼び出しを繰り返すことは、$(this)速度に特に影響を与えません。

コードのタイトループで速度が本当に問題になる場合は、JQuery選択エンジンを完全に使用しないようにそのセクションをリファクタリングすることはほぼ間違いなく価値があります。私のテストでは、セレクターの複雑さに応じて、ローカルセレクターのキャッシュから10〜50%のパフォーマンスの向上が得られ、JQueryセレクターよりもネイティブのDOMセレクターから1000%のパフォーマンスの向上が得られます。

于 2013-02-08T18:12:15.703 に答える
0

メモ化について具体的に話すことはできますが、キャッシュされたjQueryコレクションの連想配列を維持するという戦略は良い考えだと言えます。そうは言っても、いくつかのことを考慮する必要があります。

  1. 前もって0回または1回しか使用されないセレクターをキャッシュすることは必ずしも価値があるとは限りません。
  2. 要素のコレクションについて動的なもの(長さなど)を計算しようとしている場合は、値を取得する前に要素を再選択/再キャッシュする必要があります。例えば:

    var $ div = $( "div");

    $ div.length; //1だと言う

    //...ページにいくつかのdivを追加するコード

    $ div.length; //まだ1!

  3. キャッシングを「時間内に」行うことを検討します。つまり、最初に必要になったときにのみアイテムをキャッシュします。

于 2013-02-08T18:10:34.137 に答える
0

全体的なアイデアは良いものです。ただし、他の人がすでに述べたように、特に再クエリが必要なものをキャッシュしていないことに注意する必要があります。

あなたの試みが失敗した理由は、あなたが_.memoize間違って使用しているためです. 次のようになります。

var jquerySelect = _.memoize(function (selection) {
                       return $(selection);
                   });

memoize次に呼び出す関数を返します。基本的に、キャッシュを処理する関数のラッパーを作成します。

于 2013-02-08T18:21:28.123 に答える
-1

キャッシングは、jquery で従うべきベスト プラクティスです。

キャッシングを 2 つのカテゴリに分けました。

1. ローカル キャッシング: スコープが一部の関数内のみにある。

元:

function doSome(){
var elm=$('selector');
elm.something1().something2()  .... chain it on one
}

使用上の注意点:

私。非常に少数の関数によってアクセスされる要素、またはその関数のみによってアクセスされる要素をキャッシュします。

ii. 要素が動的に追加される場合は、毎回再初期化する必要があるため、ローカル キャッシュの方が優れています。

iii. キャッシュに使用される変数とともに、すべての var 宣言を一番上に保持します。

iv。一度キャッシュし、後で.filter('selector')or .filter(function) ex を使用してフィルタリングします。elm.filter(':checked').dosomething();

2.すべての機能を対象とするグローバル キャッシング

グローバルキャッシングの場合、オブジェクトを宣言し、すべてのキャッシングをその変数のキーと値のペアとして作成します。

元:

var global={};
$(document).ready(function(){
global.sel1=$('selector1');
global.sel2=$('selector2');
});

//ページの上部でグローバル変数を宣言している場合は、ドキュメント準備完了関数内に常にキャッシング変数を追加することを忘れないでください。dom には要素が存在しないため、セレクターは undefined を返します。

あなたが使用できるよりも私が好むページの下にすべてのスクリプトを配置している場合

var global={
sel1:$('selector1'),
sel2:$('selector2')
} ;

覚えておくべきポイント

  1. ラッパー要素は、グローバル キャッシュにキャッシュするのが最適です。子要素として .find() を使用して見つけることができ、通常は実質的に変更されません。(id が選択の最速の方法であるため、すべてのラッパー要素に id を保持することをお勧めします。)
  2. 頻繁に使用される要素にのみ使用してください。後で要素が追加されるセレクターには使用しないでください。
  3. グローバルなものへのアクセスは、ローカルのものへのアクセスよりもコストがかかるため、関数内でグローバル オブジェクトのローカル参照を作成します。例: function some(){ var elm=global.sel1; // elm で何かをする }

グローバル チャッシング用のセッターおよびゲッター関数

function getGlobal(selector){
//if not present create it .
if(!global[selector]){
global[selector]=$(selector);
}
return global[selector];
}

//to use it
var elm=getGlobal('selector');
于 2013-02-08T19:21:33.223 に答える