フロントエンドパフォーマンス最適化に関する補足記事

フロントエンドパフォーマンス最適化に関する補足記事

序文

私は、Web サイトのフロントエンド パフォーマンス最適化のための JavaScript と CSS、jQuery プログラミングの標準的な記述方法とベスト プラクティスを含む、フロントエンド パフォーマンス最適化に関する以前に公開された記事を調べました。フロントエンドのパフォーマンス最適化は、継続的な追求のプロセスです。前回の記事ではパフォーマンス最適化についていくつか説明しましたが、パフォーマンス最適化にはまだ長い道のりがあり、言及されていないこともたくさんあります。今日は、これまでの基礎に基づいて、一般的に使用されるパフォーマンス最適化手法のいくつかを簡単にまとめます。

オペレーター

1. 演算子を使用する場合は、代入演算を直接実行するのではなく、+=、-=、*=、\= などの演算子を使用するようにしてください。

2. ビット操作。

ビット演算は、数学演算を実行するときに高速です。ビット演算は、ブール演算や算術演算よりも高速です。たとえば、モジュロ、論理 AND、論理 OR もビット演算に置き換えられると考えられます。

クラスメートが、一般的な js ビット演算子は何ですか? と尋ねました。一般的なビット演算子には、「~、&、|、^、.<<、>>、>>>」などがあります。

ビット演算の応用については、以前の記事でも触れましたが、js 演算子の単一の縦棒「|」の使い方と機能は何でしょうか。実用的な JavaScript スキルと JS の知識も確認できます。

全般的な最適化
1. switch ステートメント。

複雑な一連の if-else ステートメントがある場合は、それらを 1 つの switch ステートメントに変換して、コードを高速化できます。case ステートメントを最も可能性の高いものから最も可能性の低いものの順に整理することで、さらに最適化できます。

例えば:

関数 getCategory(年齢) {
    var カテゴリー = "";
    スイッチ(真){
        isNaN(年齢)の場合:
            category = "年齢ではありません";
            壊す;
        ケース(年齢 >= 50 歳):
            カテゴリ = "古い";
            壊す;
        ケース(年齢 <= 20):
            カテゴリ = "赤ちゃん";
            壊す;
        デフォルト:
            カテゴリ = "若い";
            壊す;
    };
    返品カテゴリ;
}
getCategory(5); //赤ちゃん

このような少し複雑なケースでは、if/else を使用しないようにしています。もちろん、単純な判断の場合は、if/else を使用することをお勧めします。

2. ページの再描画を減らす

この項目は、私の jQuery 記事の最適化で言及されています。

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

 var str = "<div>これはテスト文字列です</div>";
/**効率が低い**/
var obj = document.getElementsByTagName("body");
(var i = 0; i < 100; i++){
    obj.innerHTML += str + i;
}
/**高効率**/
var obj = document.getElementsByTagName("body");
var arr = [];
(var i = 0; i < 100; i++){
    arr[i] = str + i;
}
obj.innerHTML = arr.join("");

3. メソッド文字列の代わりにメソッドを渡す

setTimeout() や setInterval() などの一部のメソッドは、文字列またはメソッド インスタンスをパラメーターとして受け入れます。文字列の二次解析を回避するには、メソッド オブジェクトをパラメーターとして直接渡します。

配送方法

setTimeout(test, 1); // 良い
メソッド文字列を渡す

setTimeout('test()', 1); // 悪いとは言えないが、良くないと言える

4. メソッド呼び出しの代わりにプリミティブ操作を使用する

メソッド呼び出しは、通常、プリミティブ操作をカプセル化します。高いパフォーマンス要件を持つロジックでは、パフォーマンスを向上させるために、メソッド呼び出しの代わりにプリミティブ操作を使用できます。

オリジナル操作

var min = a<b?a:b; //良い
方法の例
var min = Math.min(a, b); // 良くない

5. タイマー

継続的に実行されるコードを対象とする場合は、setTimeout ではなく setInterval を使用する必要があります。 setTimeout は毎回タイマーをリセットします。

6. 文の数を最小限に抑える

例えば:

複数の変数宣言

/**非推奨**/
var i = 1;
var j = "こんにちは";
var arr = [1,2,3];
var now = 新しい Date();
/**推進する**/
var i = 1,
    j = "こんにちは",
    arr = [1,2,3],
    now = 新しい日付();

反復値を挿入

/**非推奨**/
var name = 値[i];
私は++;
/**推進する**/
var name = values[i++];

配列とオブジェクトリテラルを使用し、コンストラクタArray()、Object()の使用は避けてください。

 /**非推奨**/
var a = 新しい配列();
0 = 1;
a[1] = "こんにちは";
a[2] = 45;
var o = 新しいオブジェクト();
o.name = "請求書";
o.年齢 = 13;
/**推進する**/
var a = [1, "こんにちは", 45];
var o = {
    名前:「ビル」、
    年齢: 13
};

型変換

1. 数値を文字列に変換します。

アプリケーション「」+1、効率は最高です。

パフォーマンスの点では、""+string>String()>.toString()>new String() です。

 String() は内部関数なので非常に高速です。
.toString() はプロトタイプ内の関数を照会する必要があるため、若干遅くなります。
new String() が最も遅いです。

2. 浮動小数点数を整数に変換します。

parseInt() の使用が間違っています。

parseInt() は、浮動小数点数と整数間の変換ではなく、文字列を数値に変換するために使用されます。

代わりに Math.floor() または Math.round() を使用する必要があります。

Math は内部オブジェクトなので、Math.floor() はメソッドや呼び出しのクエリに実際にはそれほど時間がかからず、最も高速です。

サイクル
1. 毎回取得しないように変数を定義する

/**効率が低い**/   
var divs = document.getElementsByTagName("div");    
for(var i = 0; i < divs.length; i++){   
    ...  
}    
/**効率が高く、DOM コレクションを取得するのに適しています。純粋な配列の場合は、2 つのケースにほとんど違いはありません**/  
var divs = document.getElementsByTagName("div");   
for(var i = 0, len = divs.length; i < len; i++){   
    ... 
}

2. ループ内で try-catch を使用しないでください。

try-catch-finally ステートメントは、catch ステートメントの実行中に変数を動的に構築し、現在のスコープに挿入します。これにより、パフォーマンスに一定の影響が生じます。

例外処理メカニズムが必要な場合は、ループの外で使用できます。

ループ外でtry-catchを使用する

試す {
  ( var i = 0; i < 200; i++) {} の場合
} キャッチ (e){}

3. 多数の要素のトラバースを避け、トラバース範囲を縮小するようにしてください。

スコープチェーンとクロージャの最適化
1. 範囲。

スコープは JavaScript プログラミングにおける重要な動作メカニズムであり、JavaScript の同期および非同期プログラミングと JavaScript のメモリ管理において重要な役割を果たします。 JAVASCRIPT では、次のポイントがスコープを形成できます。

関数呼び出し with ステートメントは独自のスコープを作成し、コードが実行されるスコープの長さを増加させます。
グローバルスコープ。

次のコードを例に挙げます。

 var foo = 関数() {
  var ローカル = {};
};
関数 foo();
console.log(local); //=> 未定義

var バー = 関数() {
  ローカル = {};
};
バー();
console.log(ローカル); //=> {}

/**ここでは、foo() 関数と bar() 関数を定義します。どちらも local という変数を定義することを目的としています。 foo() 関数では、var ステートメントを使用してローカル変数を宣言し、関数本体内にスコープが形成されるため、この変数はそのスコープ内で定義されます。さらに、foo() 関数の本体ではスコープ拡張は実行されないため、関数の実行後にローカル変数も破棄されます。変数は外部スコープ内ではアクセスできません。 bar() 関数では、ローカル変数は var ステートメントを使用して宣言されていません。代わりに、local はグローバル変数として直接定義されています。したがって、外部スコープはこの変数にアクセスできます。 **/

ローカル = {};
// ここでの定義は global.local = {}; と同等です。

2. スコープチェーン

JAVASCRIPT プログラミングでは、スコープ チェーンの典型的な表現である、複数層のネストされた関数を含むシナリオに遭遇します。

関数foo(){
  var val = 'hello';
  関数バー() {
    関数baz() {
      global.val = 'world;'
    };
    バズ();
    console.log(val); //=> こんにちは
  };
  バー();
};
関数 foo();

/** `JAVASCRIPT` では、変数識別子は現在のスコープから外側に向かってグローバル スコープまで検索されます。したがって、`JAVASCRIPT` コード内の変数へのアクセスは、外向きにのみ実行でき、逆向きには実行できません。 baz() 関数の実行により、グローバル スコープ内にグローバル変数 val が定義されます。 bar() 関数では、識別子 val にアクセスする場合、検索の原則は内側から外側に向かって行われます。つまり、bar 関数のスコープ内で見つからない場合は、上位層、つまり foo() 関数のスコープ内で検索されます。しかし、誰もが混乱する鍵はここにあります。この識別子アクセスは、foo() 関数のスコープ内で一致する変数を見つけ、外部の検索を続行しないため、baz() 関数で定義されたグローバル変数 val はこの変数アクセスには影響しません。 **/

3. スコープチェーン上の検索回数を減らす

/**効率が低い**/
(var i = 0; i < 10000; i++){
    var but1 = document.getElementById("but1");
}
/**高効率**/
/**グローバル検索を避ける**/
var doc = ドキュメント;
(var i = 0; i < 10000; i++){
    var but1 = doc.getElementById("but1");
}
/** 上記のコードでは、2 番目のケースでは、まず関数内でグローバル オブジェクトの変数を保存し、その後変数に直接アクセスしますが、1 番目のケースでは、グローバル環境に到達するまでスコープ チェーンを毎回トラバースします。2 番目のケースは実際には 1 回しかトラバースされませんが、1 番目のケースは毎回トラバースされることがわかります。この違いは、マルチレベル スコープ チェーンと複数のグローバル変数の場合に非常に明白になります。スコープ チェーン内の検索回数は O(n) です。 `document` を指すローカル変数を作成することで、検索をグローバルなものに制限し、この関数のパフォーマンスを向上させることができます。 **/

4. 終了

JAVASCRIPT での識別子の検索は、内部から外部への原則に従います。

関数foo(){
  var local = 'こんにちは';
  関数()を返す{
    ローカルを返します。
  };
}
var bar = foo();
console.log(bar()); //=> こんにちは

/** ここで示されている、外側のスコープが内側のスコープにアクセスできるようにする手法は、クロージャと呼ばれます。高階関数の適用により、foo() 関数のスコープが `拡張` されます。 foo() 関数は、foo() 関数のスコープ内に存在する匿名関数を返すため、foo() 関数のスコープ内のローカル変数にアクセスし、その参照を保存できます。この関数はローカル変数を直接返すため、bar() 関数を外部スコープで直接実行してローカル変数を取得できます。 **/

クロージャは、JAVASCRIPT の高度な機能です。内部変数参照を持つ関数を関数から取り出すため、関数の実行後、内部変数へのすべての参照が解放されるまで、スコープ内の変数は必ずしも破棄されるわけではありません。したがって、クロージャを適用すると、メモリが解放されなくなる可能性が高くなります。

閉鎖管理が良好です。

ループ イベント バインディング、プライベート プロパティ、パラメーター付きコールバックなどにクロージャを使用する必要がある場合は、詳細に注意してください。

ループバインディングイベントでは、6 つのボタンがあり、それぞれが 6 つのイベントに対応するというシナリオを想定します。ユーザーがボタンをクリックすると、対応するイベントが指定された場所に出力されます。

var btns = document.querySelectorAll('.btn'); // 6 つの要素
var 出力 = document.querySelector('#output');
var イベント = [1, 2, 3, 4, 5, 6];
// ケース1
(var i = 0; i < btns.length; i++) の場合 {
  btns[i].onclick = 関数(evt) {
    output.innerText += 'クリックされました' + events[i];
  };
}
/** ここでの最初の解決策は、明らかに典型的なループ バインディング イベント エラーです。ここでは詳細には触れません。詳細については、ネットユーザーへの私の回答を参照してください。2 番目と 3 番目の解決策の違いは、クロージャによって渡されるパラメーターにあります。 **/
// ケース2
(var i = 0; i < btns.length; i++) の場合 {
  btns[i].onclick = (function(index) {
    関数(evt)を返す{
      output.innerText += 'クリックされました' + events[index];
    };
  })(私);
}
/** 2 番目のソリューションでは、現在のループ インデックスがパラメーターとして渡されますが、後者のソリューションでは、対応するイベント オブジェクトが直接渡されます。実際、後者は大規模データ アプリケーションに適しています。JavaScript の関数型プログラミングでは、関数を呼び出すときに渡されるパラメーターは基本型オブジェクトであるため、関数本体で取得される仮パラメーターはコピーされた値になり、この値は関数本体のスコープ内でローカル変数として定義されます。イベント バインディングが完了したら、イベント変数を手動で逆参照して、外部スコープでのメモリ使用量を削減できます。さらに、要素が削除されると、対応するイベント リスニング関数、イベント オブジェクト、およびクロージャ関数も破棄され、リサイクルされます。 **/
//ケース3
(var i = 0; i < btns.length; i++) の場合 {
  btns[i].onclick = (function(イベント) {
    関数(evt)を返す{
      output.innerText += 'クリックされました' + イベント;
    };
  })(イベント[i]);
}

閉鎖の罠を避ける

クロージャは強力なツールですが、パフォーマンスの問題の主な原因の 1 つでもあります。クロージャを不適切に使用すると、メモリ リークが発生する可能性があります。

クロージャのパフォーマンスは、内部メソッドを使用する場合ほど良くなく、外部メソッドを再利用する場合よりもさらに悪くなります。

IE 9 ブラウザの DOM ノードは COM オブジェクトとして実装されているため、COM メモリ管理は参照カウントによって行われます。参照カウントの問題の 1 つは循環参照です。DOM がクロージャ (イベント ハンドラなど) を参照し、クロージャの上位レベルの要素が DOM を参照すると、循環参照が発生し、メモリ リークが発生します。

機能を有効活用する

匿名関数を使用して、コードを最も外側のレベルでラップします。

 ;(function() { // メインビジネスコード})();

さらに高度なものもあります:

 ;(関数(win, doc, $, 未定義) {
  // メインビジネスコード})(window, document, jQuery);

RequireJS、SeaJS、OzJS などのフロントエンドのモジュール読み込みソリューションでも同様の形式が採用されています。

 /**JS が必要です**/
定義(['jquery'], 関数($) {
  // メインビジネスコード});
/**SeaJS**/
定義('モデル'、['dep'、'アンダースコア']、関数($、_) {
  // メインビジネスコード});

コールバック関数を有効活用する<br />Webページを作成する過程では、よく使う箇所を関数にカプセル化することがよく行われます。関数をカプセル化するときは、コールバック関数を有効に活用してください。

以下にいくつか例を挙げます。

関数 getData(callBack){
    $.ajax({
        url:"",
        データ:{}、
        データ型:"json",
        タイプ:"取得",
        成功:関数(データ){
            コールバック(null,データ)
        }
    })

}

これを呼び出すと、次の操作を実行できます。

 getData(関数(エラー,データ){
 コンソール.log(データ)
})

配列に要素を挿入する最も速い方法<br />配列に要素を挿入することは、非常に一般的なタスクです。 push を使用して配列の末尾に要素を挿入したり、unshift を使用して配列の先頭に要素を挿入したり、splice を使用して配列の途中に要素を挿入したりできます。 しかし、これらの既知の方法は、より効率的な方法が存在しないことを意味するものではありません。

最後に要素を挿入

2つの配列があります

var arr = [1,2,3,4,5];
var arr2 = [];

テストは次のとおりです。

 arr[arr.length] = 6; // 最速 arr.push(6); // 34.66% 遅い
arr2 = arr.concat([6]); // 85.79%遅い

要素を前に挿入

var arr = [1,2,3,4,5];
arr.unshift(0); 
[0].concat(arr);

発見する:

 [0].concat(arr); // 高速化 arr.unshift(0); // 64.70% 低速化

配列の中央に要素を追加する

splice を使用すると、配列の中央に要素を追加するだけで済みます。これは最も効率的な方法でもあります。

 var items = ['1', '2', '3', '4'];
items.splice(items.length / 2, 0, 'hello');

<<:  ホバープロンプトにはvue2+elementuiを使用する

>>:  純粋な HTML タグにどれくらい精通していますか?

推薦する

htmlダウンロード機能の詳しい説明

新しいプロジェクトは基本的に終了しました。フロントエンドとバックエンドを分離して統合を完了したのは初...

CentOS8でのDockerの使い方の詳しい説明

1. CentOS8でのDockerのインストール カール https://download.doc...

HTML シンボルからエンティティへのアルゴリズムのチャレンジ

チャレンジ:文字列内の文字 &、<、>、" (二重引用符)、および &...

MySQL 8.0 の非表示列に対する基本操作

目次01 非表示の列を作成する02 非表示の列に対する基本操作03 非表示の列メタデータ04 主キー...

CSS スタイルにおける中国語フォントのフォントファミリーに対応する英語名の詳細な説明

ソングティ: SimSun太字: SimHeiマイクロソフト YaHei: マイクロソフト YaHe...

MySQL の一般的な SQL ステートメントの概要

1. mysqlエクスポートファイル: SELECT `pe2e_user_to_company`....

CSS で波の効果を作成するためのアイデア

以前、純粋な CSS を使用して波の効果を実現する方法をいくつか紹介しました。それらについては、次の...

Kali Linux インストール VMware ツールのインストール プロセスと VM インストール vmtools ボタン グレー

Xiaobai は vmtools のインストールを記録します。 1. 意義と機能: VMWARE ...

MySQL インデックス使用状況監視スキル (収集する価値あり!)

概要リレーショナル データベースでは、インデックスは、データベース テーブル内の 1 つ以上の列の値...

javascript:void(0) の意味と使用例

voidキーワードの紹介まず、void キーワードは JavaScript で非常に重要なキーワード...

MySQL 8.0.22 のインストールと設定方法のグラフィックチュートリアル

この記事ではMySQL 8.0.22のインストールと設定について記録します。具体的な内容は以下のとお...

CentOS8 Linux 8.0.1905 のインストール手順(図解)

現在、CentOS の最新バージョンは CentOS 8 です。次に、CentOS Linux 8....

WebWorkerはJavaScriptサンドボックスの詳細をカプセル化します

目次1. シナリオ2. IJavaScriptShadowboxを実装する2.1 メインスレッドの実...

MySQL 外部キー (FOREIGN KEY) の使用例の詳細な説明

はじめに: すべてのデータを 1 つのテーブルに保存することのデメリット表の構成構造は複雑で不明瞭で...