失敗した jQuery 最適化試行の概要_jquery

WBOY
リリース: 2016-05-16 18:11:01
オリジナル
784 人が閲覧しました

(これは jQuery のパフォーマンスが優れているという意味ではありません。逆に、比較的閉じられたライブラリであり、外部から最適化することができないとしか言​​えません)。この記事では、最適化に失敗した経験を記録します。
最適化のアイデア
今回の最適化のアイデアはデータベースから来ています。データベースを最適化するとき、「多数の操作を 1 つのトランザクションにまとめてコミットすると効率が効果的に向上する」とよく言われます。データベースのことはあまり詳しくないので理由は分かりませんが、「トランザクション」という考え方が方向性を示してくれました(違うんですが…)。
そこで、jQuery に「トランザクション」の概念を導入し、トランザクションの「オープン」と「送信」によって外部から jQuery を最適化しました。最も重要なことは、各関数のループ数を減らすことです。 。
ご存知のとおり、jQuery の DOM 操作は get all と set first に基づいており、DOM 属性/スタイルの設定に使用される操作はほとんどすべて、jQuery.access 関数の核心部分です。 、ループのコードは次のとおりです:

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

// 1 つの属性を設定します
if ( value !== unknown ) {
// オプションで、 exec が true の場合に関数の値が実行されます
exec = !pass && exec && jQuery.isFunction(value) ;
for ( var i = 0; i fn(
elems[i],
key,
exec ? value.call(elems[i]) , i, fn(elems[i], key)) : value,
pass
);
return elems;


例、jQuery.fn。css 関数は次のとおりです:


コードをコピーします コードは次のとおりです:
jQuery.fn.css = function( name, value ) {
// 'unknown' の設定は何も行われません
if ( argument.length === 2 && value === unknown ) {
戻り値;
}
戻り値 jQuery.access( this, name, value, true, function( elem, name, value ) {
戻り値 !== 未定義 ?
jQuery. style( elem, name, value ) :
jQuery.css( elem, name );
}; したがって、次のコードは5000 個の div 要素を選択し、10000 個のノードをループするには:
jQuery('div').css('height', 300).css('width', 200); 私の心の中では、 「トランザクション」もデータベース操作と同様に、すべての操作を保存し、「トランザクションの送信」時に一律に実行することで、10,000 件のノードアクセスを 5,000 件に削減でき、これは「1 倍」のパフォーマンス向上に相当します。

簡単な実装
「トランザクション」jQuery 操作では、2 つの関数が提供されます。
begin: 「トランザクション」を開き、トランザクション オブジェクトを返します。このオブジェクトには jQuery のすべての機能が含まれていますが、関数の呼び出しはすぐには有効にはならず、「トランザクションの送信」後にのみ有効になります。
コミット: 「トランザクション」を送信して、以前に呼び出されたすべての関数が有効になり、元の jQuery オブジェクトが返されることを確認します。
次の実装も非常に便利です。
「トランザクション オブジェクト」を作成し、jQuery.fn 上のすべての関数をそのオブジェクトにコピーします。 関数を呼び出す際には、呼び出される関数名と関連パラメータをあらかじめ用意された「キュー」に追加します。 トランザクションがコミットされると、選択された要素に対してトラバーサルが実行され、「キュー」内のすべての関数がトラバーサル内の各ノードに適用されます。
コードは次のとおりです:




コードをコピーします


コードは次のとおりです:},
key,
func;
// jQuery.fn
for (jQuery.fn の key) に関数をコピーします。 {
func = jQuery.fn[key]; (typeof func == ' function') {
//キーが常に最後のループ値である for ループのため、ここで問題が発生します
//そのため、妥当性を保証するためにクロージャを使用する必要がありますキーの(LIFT効果)
(function( key) {
proxy[key] = function() {
//関数呼び出しをキューに入れます
this._queue.push([ key, slide.call(arguments, 0)]);
return this
})(key);
}
}
;
proxy.commit = jQuery.fn.commit;
jQuery.fn.commit = function() {
var core = this._core ,
queue = this._queue;
// 各ループは 1 つだけ
core.each(function() {
var i = 0,
item,
jq = jQuery( this);
//すべての関数
for (; item = queue[i]; i ) {
jq[item[0]].apply(jq, item[1]); >}
});
これを返します
};
テスト環境
テストでは次の条件を使用します:
コンテナー内に配置された 5000 div (
)。
$('#container>div') を使用して、これらの 5000 div を選択します。
各 div は、ランダムな背景色 (randomColor 関数) と 800px 未満のランダムな幅 (randomWidth 関数) を設定する必要があります。
テストに参加するには 3 つの呼び出し方法があります:
通常の使用法:
コードをコピー コードは次のとおりです:

$('#container>div')
.css('background-color', randomColor)
.css('width', randomWidth);

単一ループ メソッド:
コードをコピーしますは次のとおりです:

$('#container>div').each(function() {
$(this).css('background-color', randomColor).css( 'width'、randomWidth) ;


ビジネスメソッド:
$('#container>div')
.begin()
.css('background-color', randomColor)
.css(' width', randomWidth)
.commit();


オブジェクト割り当てメソッド:

コードをコピーします コードは次のとおりです:
$('#container>div').css({
'background -color':randomColor,
'width' :randomWidth
});


テスト ブラウザとして Chrome 8 シリーズを選択します (IE でテストするとハングするだけです)。

残念な結果
当初の予測結果は、トランザクション方式はシングルループ方式よりも遅いにもかかわらず、シングルループ方式の効率が通常の使用方式よりもはるかに高いというものでした。ループ メソッドを使用すると、通常のメソッドよりも高速になるはずです。オブジェクト割り当てメソッドは実際には jQuery によって内部的にサポートされる単一ループ メソッドであり、これが最も効率的です。
残念ながら結果は以下の通りです。
通常の使用法、シングルループ法、トランザクション法、オブジェクト代入法
18435ms 18233ms 18918ms 17748ms
結果から見ると、トランザクション法が最も遅いものとなっています。方法。同時に、単一ループと通常の使用の間に明らかな利点はなく、jQuery の内部で実装されたオブジェクト割り当てメソッドに依存しても大きなギャップはありません。
5000 要素の演算はすでに非常に巨大なループであるため、そのような巨大なループによってパフォーマンスの差を広げることはできません。最も一般的に使用される約 10 要素の演算には、明らかな利点がある可能性はさらに低く、むしろ欠点が拡大する可能性があります。 。
その理由は、シングル ループ メソッド自体には明らかなパフォーマンスの向上がないため、シングル ループに依存しており、当然ながらシングル ループに基づいて外部で構築されたトランザクション メソッドでもあります。トランザクション オブジェクトの作成、関数キューの保存、関数キューの走査など、追加のオーバーヘッドが必要です。通常の使用法では結果が失われるのは当然です。
現時点で、「トランザクション」を模倣する最適化手法は失敗していると言えるでしょう。ただし、この結果はさらに分析することができます。

パフォーマンスはどこにありますか?
まず、コードの使用方法を分析し、通常の使用方法とテストで最も速いオブジェクト割り当て方法を比較します。この 2 つの違いはループ内にあるだけです (jQuery の内部問題はここでは脇に置きます。実際、jQuery.access の実装が不十分であるため、オブジェクトの割り当て方法が妨げられますが、幸いなことにそれは深刻ではありません)。 )、通常の使用は 10,000 要素です。オブジェクト割り当て方法は 5000 要素です。したがって、18435 - 17748 = 687ms は 5000 個の要素をループするのにかかる時間であると単純に考えることができ、これは実行プロセス全体の約 3.5% を占めますが、実際には実行プロセス全体のバックボーンではありません。実際には最適化の必要はありません。
では、経費の残りの 96.5% はどこに使われるのでしょうか? Doglas 氏の言葉を思い出してください。「実際には、JavaScript が遅いのではありません。遅いのは DOM 操作です。」実際、関数呼び出しなどの基本的な消費を除く残りの 96.5% のオーバーヘッドのうち、少なくとも 95% の時間が DOM 要素のスタイル変更後の再レンダリングに費やされます。

この事実を発見した後、実際にはより正しい最適化の方向性が得られました。これはフロントエンドのパフォーマンスの基本原則の 1 つでもあります。多数の子要素を変更する場合は、最初にルートの親 DOM ノードを移動します。 DOM ツリーから外されます。したがって、次のコードを使用して再度テストするとします。


コードをコピーします コードは次のとおりです:

//$('#container') を再利用しないのはすでに悪いです
$('#container').detach().find('div')
.css('background - color',randomColor)
.css('width',randomWidth);
$('#container').appendTo(document.body);

テスト結果は常に残ります約 900 ミリ秒では、以前のデータよりも 1 桁も高いわけではなく、実際の最適化は成功しています。

教訓と要約
必ず正しいパフォーマンスのボトルネックを見つけて、それを最適化してください。盲目的な推測は間違った極端な道を導くだけです。
データは語る、誰もデータの前で語るべきではない!
「トランザクション」の方向性は間違っていないと思いますが、jQuery が「トランザクション」の概念をネイティブでサポートできるのであれば、他に最適化できる点はありますか?たとえば、トランザクションは DOM ツリーから親要素を自動的に削除します...
関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!