ホームページ  >  記事  >  ウェブフロントエンド  >  JQuery each() 関数はループ DOM のパフォーマンスをどのように最適化しますか

JQuery each() 関数はループ DOM のパフォーマンスをどのように最適化しますか

WBOY
WBOYオリジナル
2016-05-16 17:47:001120ブラウズ

jQuery の具体的な実装を知らずに、jQuery を使用するレベルに留まると、非常に簡単に問題が発生します。このフレームワークの API 設定が人々を迷わせている疑いがあるため、私は最近 jQuery をあまり使いたくないのです。

コードをコピー コードは次のとおりです。

$.fn.beautifyTable = function(options) ) {
//デフォルトの構成項目を定義し、オプションでそれらをオーバーライドします。
return this.each(function() {
var table = $(this),
tbody = table.children ('tbody')、
tr = tbody.children('tr')、
th = tbody.children('th')、
td = tbody.children('td'); >//単一のコンテンツ クラス
table.addClass(option.tableClass);
th.addClass(options.headerClass); //1
td.addClass(options.cellClass); >//奇数行と偶数行 class
tbody.children('tr:even').addClass(options.evenRowClass); //3
tbody.children('tr:odd').addClass(options. oddRowClass); //4
//Alignment
tr.children('th,td').css('text-align', options.align); //5
//マウスホバーを追加
tr.bind('mouseover', addActiveClass); //6
tr.bind('mouseout',removeActiveClass); //7
//クリックして色を変更します
tr.bind( 'クリック', toggleClickClass); //8
});
一般に、このコードは優れており、アイデアが明確で、ロジックが明確で、やりたいことがコメントで明確に説明されています。しかし、作者によると、テーブルに 120 行がある場合、IE はスクリプトの実行時間が長すぎることをすでに反映しています。パフォーマンスの観点から見ると、この機能の効率は決して高くないか、あるいは極端に低いことは明らかです。

そこで、コードレベルから分析を始めました。これは、標準的な jQuery プラグイン関数です。 return this.each(function( ) { .. };) という形式のコードがあります。 ; 作者がこのコードを書いたときに何も考えずにスクリプトに従っていたのではなく、jQuery の関数が何をするのかを理解したはずです。

簡単に言うと、jQuery.fn のほとんどの関数は each への呼び出しであり、選択された要素を自然に走査し、要素に対して指定された操作を実行します。したがって、上記のコードを見て、実行されたトラバーサルの数を確認してください。120 行のみが選択されており、各行に 6 つの列と 1 行のヘッダーがあると仮定します。
Traverse th、headerClass の数を追加します。要素は6です。
td をトラバースし、cellClass を追加すると、要素の数は 6*120=720 になります。
すべての tr から奇数を見つけるには、すべての tr を 1 回走査する必要があり、要素数は 120 です。
奇数の tr をトラバースし、evenRowClass を追加します。要素の数は 120/2=60 です。
すべての tr から偶数を見つけるには、すべての tr を 1 回走査する必要があり、要素数は 120 です。
偶数の tr をトラバースし、oddRowClass を追加すると、要素の数は 120/2=60 になります。
th と td をすべて走査し、text-align を追加します。要素の数は 120*6 6=726 です。
すべての tr を走査し、mouseover イベントを追加します。要素の数は 120 です。
すべての tr をトラバースし、mouseout イベントを追加します。要素の数は 120 です。
すべての tr をトラバースし、クリック イベントを追加します。要素の数は 120 です。
便宜上、トラバーサル中の要素へのアクセスには 10 ミリ秒かかると仮定します。では、この関数には合計でどれくらいの時間がかかるのでしょうか?この関数は合計 2172 個の要素を検出し、21720 ミリ秒、つまり 21 秒かかりました。明らかに、IE はスクリプトに時間がかかりすぎたと報告するはずです。

効率が低い理由がわかったので、当然のことながら、コード内のコメントの数字に従ってループをマージする方法を見つける必要があります。上記では、少なくとも次の点をマージできます:
3 と 4 は 120 60 120 60 から 120 まで 1 つのサイクルに結合でき、240 の削減になります。 1、2、5 は 1 つのサイクルに結合できます。 6 720 726 から 726 に、726 の減少です。6. 7 と 8 を 1 つのサイクルに組み合わせることができ、120 120 120 から 120 に変化し、240 の減少になります。さらに、3、4 と 6、7、8 を 1 つのサイクルに組み合わせることができ、120 ずつ減少し続けます。累積的に、合計 240 726 240 120 = 1326 要素演算、合計 13260 ミリ秒が削減されました。最適化後、関数の消費時間は 21720-13260=8460 ミリ秒、つまり 8 秒になります。
ここで質問があるかもしれませんが、テーブルの構造から、すべての th 要素と td 要素は tr 内にある必要があります。なぜ 1、2、5 の 3 ステップのサイクルも tr に入れたらよいのでしょうか。ループを作成してネストされたループを形成すると、より高速になるのではないでしょうか?
ここでこれが行われない主な理由は 2 つあります。
まず、1、2、5 をどこに配置しても、すべての th 要素と td 要素への 1 回のアクセスは減りません。
一方、セレクター $('th, td') は、sizzle での getElementsByTagName 関数への 2 回の呼び出しに変換されます。1 回目はすべての th を取得し、2 回目はすべての td を取得してから収集します。合併の彼ら。 getElementsByTagName は組み込み関数であるため、この関数はループを持たないと考えることができます。つまり、複雑さは O(1) です。同じコレクションのマージには、演算である Array の関連関数が使用されます。メモリ上での計算量も O(1) です。

逆に、セレクター $('th, 'td) が tr 要素のループで使用されている場合、関数がどの要素で呼び出されるかに関係なく、getElementsByTagName が tr 要素で 2 回呼び出されます。 , 関数の実行時間は同じなので、trのループ時に使用すると関数呼び出しが119*2多くなり、効率は上がらずに下がってしまいます。
シズル セレクターの基本的な知識も、jQuery コードの最適化に役立つ非常に重要な側面であることがわかります。
JavaScript にすべてをさせないでください。

前回の基本的な最適化によれば、時間は 21 秒から 8 秒に短縮されましたが、8 秒という数字は明らかに受け入れられません。
コードをさらに分析すると、実際、ループ トラバーサルは言語レベルで行われ、その速度は非常に高速であることがわかります。各要素に対して実行される操作は、jQuery によって提供される関数です。トラバーサルと比較すると、ほとんどのリソースが消費されます。トラバーサル中に要素にアクセスするのに 10 ミリ秒かかる場合、率直に言って、addClass の実行には少なくとも 100 ミリ秒が消費されます。

したがって、効率をさらに最適化するには、要素に対する操作を減らすことから始める必要があります。コードを注意深く検討した結果、この関数のスタイルには、少なくとも次のような多くの変更が加えられていることがわかりました。
Add class to all th.
すべての TD にクラスを追加します。
tr の奇数行と偶数行にクラスを追加します。
すべての th と td に text-align スタイルを追加します。
実際、CSS 自体には子孫セレクターがあり、ブラウザーによる CSS のネイティブ解析は、JavaScript で要素にクラスを 1 つずつ追加するよりもはるかに効率的であることがわかっています。

したがって、CSS が制御可能である場合、この関数には 2 つの構成項目 headerClass と cellClass を含めるべきではなく、可能な限り CSS で構成する必要があります:
コードをコピーします コードは次のとおりです:

.Beautiful-table th { /* headerClass の内容*/ }
. beautiful -table td { /* content of cellClass*/ }

さらに、tr の奇偶行スタイルについては、一部のブラウザでは n 番目の子疑似クラスを使用して実装できます。ただし、この疑似クラスをサポートしていないブラウザでのみ、機能検出を使用して addClass を使用してスタイルを追加できます。もちろん、IE シリーズを最適化したいだけの場合は、この項目は無視して構いません。

nth-child 擬似クラスを検出するには、次のアイデアを使用できます。スタイルシートを作成し、#test span:nth-child (odd) { display: block などのルールを作成します。 ; } 。対応する HTML 構造、ID テストを持つ div を作成し、その中に 3 つのスパンを配置します。

スタイルシートと div を DOM ツリーに追加します。 1 番目と 3 番目のスパンの実行時の表示スタイルを確認し、ブロックになっている場合は、疑似クラスがサポートされていることを示します。作成したスタイルシートと div を削除し、プローブの結果をキャッシュすることを忘れないでください。最後に、すべての th 要素と td 要素に text-align スタイルを追加することも、CSS を通じて最適化できます。どの配置が追加されるかわからないため、さらにいくつかのスタイルを記述します。
コードをコピー コードは次のとおりです。 :

/* CSS スタイル*/
. beautiful-table-center th,. beautiful-table-center td { text-align: center ! important }
. beautiful- table-rightright th, . beautiful-table-rightright td { text-align: rightright ! important; }
. beautiful-table-left th,. beautiful-table-left td { text-align: left ! important }
/* javascript */
table.addClass('Beautiful-table-' options.align);

もちろん、上記の最適化は CSS を制御することに基づいています。 、CSS スタイルにアクセスできない場合、たとえば、これは完全に制御できないサードパーティによって使用される一般的なプラグイン機能である場合はどうすればよいでしょうか。完全に不可能というわけではありません。
document.styleSheets など、ページ内のすべての CSS ルールを見つけます。すべてのルールを調べて、構成アイテム内の headerClass、cellClass などを取り出します。必要ないくつかのクラスのすべてのスタイルを抽出し、それらを自分で新しいセレクター (Beautiful-table th など) に組み立てます。作成したセレクターを使用して新しいスタイルシートを生成し、DOM ツリーに追加します。あとは、 beautiful-table クラスをテーブルに追加するだけで完了です。

もちろん、上記のアプローチは実際にはかなり時間がかかります。結局のところ、スタイルシートを調べてスタイルシートを作成する必要があります。効率の向上に大きく役立つかどうかは、ページのサイズに応じて異なります。これを使用するかどうかは、機能設計者の具体的なニーズによって異なります。

一般に、できるだけ少ない JavaScript を実行し、より多くのスタイル設定タスクを CSS に渡すことで、ブラウザーのレンダリング エンジンがそれを完了し、この関数は addClass と css の呼び出しに対してさらに最適化できると仮定します。には 100 ミリ秒かかりますが、この最適化により、元の 120 726 = 846 の操作が直接削除され、84600 ミリ秒の時間が節約されます (もちろん誇張ですが、関数全体の消費量という観点からすると、これは実際には非常に大きな部分です)。

この記事では、jQuery のさまざまな実装レベルの最適化のみを目的としており、jQuery の実行プロセス全体の分析、詳細な導入、最適化の方向性についてのみ説明し、いくつかの基本的な最適化方法については触れません。 as: まずテーブル全体を DOM ツリーから削除し、すべての操作が完了した後で再描画を減らすためにテーブル全体を DOM に戻します。正しいイベント バブリング モデルによって引き起こされる繰り返しイベント関数の実行を減らすために、mouseover と Mouseout を MouseEnter と MouseLeave に変更します。 th や td などの単純な要素の選択では、ネイティブの getElementsByTagName を使用することが優先され、セレクターのシズル分析の時間を排除します。

最後に、この記事では、フロントエンド開発者にとって、ブラウザはブラックボックスかもしれないが、事前にある程度理解できていれば、多くのフレームワーク、ツール、ライブラリがオープンであることを説明したいと思います。それを使用することは、間違いなく個人の技術を向上させ、最終製品の品質を最適化するのに役立ちます。「それを知っているが、その理由を知らない」という状況は非常にタブーです。
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。