目次
スコープに注意してください
適切な方法を選択してください
最小化语句数
优化DOM交互
ホームページ ウェブフロントエンド jsチュートリアル JavaScript のベスト プラクティスの詳細 - パフォーマンス

JavaScript のベスト プラクティスの詳細 - パフォーマンス

Mar 07, 2017 pm 03:04 PM

スコープに注意してください

グローバル ルックアップを避ける

例:

function updateUI(){
    var imgs = document.getElementByTagName("img");
    for(var i=0, len=imgs.length; i<len; i++){
        imgs[i].title = document.title + " image " + i;
    }
    var msg = document.getElementById("msg");
    msg.innnerHTML = "Update complete.";
}
ログイン後にコピー

この関数はまったく正常に見えるかもしれませんが、グローバル ドキュメント オブジェクトへの 3 つの参照が含まれています。ページ上に複数の画像がある場合、for ループ内のドキュメント参照が複数回、場合によっては数百回実行され、そのたびにスコープ チェーン検索が実行されます。ドキュメント オブジェクトを指すローカル変数を作成すると、グローバル検索を制限することでこの関数のパフォーマンスを向上させることができます。

function updateUI(){
    var doc = document;
    var imgs = doc.getElementByTagName("img");
    for(var i=0, len=imgs.length; i<len; i++){
        imgs[i].title = doc.title + " image " + i;
    }
    var msg = doc.getElementById("msg");
    msg.innnerHTML = "Update complete.";
}
ログイン後にコピー

ここでは、最初にドキュメント オブジェクトをローカル doc 変数に格納してから、残りのコードで元のドキュメントを置き換えます。 。元のバージョンと比較すると、この関数にはグローバル ルックアップが 1 つだけ含まれており、明らかに高速になっています。

適切な方法を選択してください

1. 不必要な属性検索を回避します

定数値の取得は非常に効率的なプロセスです

var value = 5;
var sum = 10 + value;
alert(sum);
ログイン後にコピー

コードは、数値 5、変数値、数値 10、変数合計の 4 つの定数値検索を実行します。 。

JavaScript での配列要素へのアクセスは、単純な変数検索と同じくらい効率的です。したがって、次のコードは前の例と同じくらい効率的です:

var value = [5,10];
var sum = value[0] + value[1];
alert(sum);
ログイン後にコピー

その名前のプロパティの検索はプロトタイプ チェーンで実行する必要があるため、オブジェクトのプロパティの検索は変数または配列にアクセスするよりも時間がかかります。 属性の検索が多いほど、実行時間は長くなります。

var values = {first: 5, second: 10};
var sum = values.first + values.second;
alert(sum);
ログイン後にコピー

このコードは、2 つの属性ルックアップを使用して合計の値を計算します。属性検索を 1 回または 2 回実行しても、重大なパフォーマンスの問題は発生しませんが、数百回または数千回実行すると、実行速度が確実に低下します。

単一の値を取得する複数の属性ルックアップには注意してください。例:

var query = window.location.href.substring(window.location.href.indexOf("?"));
ログイン後にコピー

このコードには、6 つのプロパティ検索があります: window.location.href.substring() が 3 回、window.location.href.indexOf() が 3 回です。 コード内のポイントの数を数えるだけで、ルックアップの数が決まります。 このコードでは window.location.href を 2 回使用し、同じ検索を 2 回実行するため、特に効率が悪くなります。

オブジェクトのプロパティを複数回使用した場合は、ローカル変数に保存する必要があります。以前のコードは次のように書き換えることができます:

var url = window.locaiton.href;
var query = url.substring(url.indexOf("?"));
ログイン後にコピー

このバージョンのコードには属性検索が 4 つしかなく、元のバージョンと比較して 33% 節約されます。

一般的に言えば、アルゴリズムの複雑さを軽減できる限り、可能な限り軽減する必要があります。ローカル変数を使用して、プロパティの検索をできる限り値の検索に置き換えます。さらに、数値配列の場所または名前付きプロパティ (NodeList オブジェクトなど) でアクセスできる場合は、数値の場所を使用します。

2. ループを最適化する

ループの基本的な最適化手順は次のとおりです。

(1) デクリメント反復 - ほとんどのループは、0 から始まり特定の値まで増加する反復子を使用します。多くの場合、ループを通じて最大値から開始して反復子をデクリメントする方が効率的です。

(2) 終了条件の簡略化 - 終了条件はループ処理が実行されるたびに計算されるため、可能な限り高速であることが保証されなければなりません。これは、プロパティの検索やその他の操作を回避することを意味します。

(3) ループ本体を簡素化します - ループは最も実行されるため、最大限に最適化されていることを確認し、ループの他の集中的な計算を簡単に削除できるようにします。

(4 ポストテスト ループを使用する - 最も一般的に使用される for ループと while ループはプレテスト ループです。do-while などのポストテスト ループは、初期終了条件の計算を回避できるため、より高速に実行されます。

以下は基本的な for ループです:

for(var i=0; i < value.length; i++){
    process(values[i]);
}
ログイン後にコピー

このコードでは、変数 i が 0 から値配列内の要素の合計数まで増加します。ループは、以下に示すように i を減少させるように変更できます。

for(var i=value.length -1; i >= 0; i--){
    process(values[i]);
}
ログイン後にコピー

終了条件は、value.length 0 から簡略化されます。

次のように、ループをテスト後のループに変更することもできます:

var i=values.length -1;
if (i> -1){
    do{
        process(values[i])
    }while(--i>=0) //此处有个勘误,书上终止条件为(--i>0),经测试,(--i>=0)才是正确的
}
ログイン後にコピー

ここでの主な最適化は、終了条件とデクリメント演算子を組み合わせることです。 「ポストテスト」ループを使用する場合、空の配列により余分なループが発生することを確認する必要があります。 「pre-test」ループは回避できます

3. ループするときにループを展開します

。はい、多くの場合、ループを削除して複数の関数呼び出しを使用する方が高速です。値の配列に要素が 3 つだけあると仮定します。各要素で process() を直接呼び出すことで、ループの設定と終了条件の処理に伴う追加のオーバーヘッドを排除でき、コードの実行を高速化できます。

//消除循环
process(values[0]);
process(values[1]);
process(values[2]);
ログイン後にコピー

ループ内の反復回数を事前に決定できない場合は、次のことを検討してください。 Duff デバイスと呼ばれる手法を使用します。Duff デバイスの基本的な概念は、反復回数が 8 の倍数であるかどうかを計算してループを分割することです。

Andrew B. King は、より高速な Duff デバイス手法を提案しました。 do-while ループを 2 つの別々のループに分割する例を次に示します。

var iterations = Math.floor(values.length / 8);
var leftover = values.length % 8;
var i = 0;

if(leftover>0){
    do{
        process(values[i++]);
    }while(--leftover > 0);
}
do{
    process(values[i++]);
    process(values[i++]);
    process(values[i++]);
    process(values[i++]);
    process(values[i++]);
    process(values[i++]);
    process(values[i++]);
    process(values[i++]);
}while(--iterations > 0);
ログイン後にコピー

この実装では、残りの計算部分は実際のループでは処理されませんが、8 による除算演算が実行されます。初期化ループ。追加の要素が処理されると、メイン ループが毎回 8 回実行されます。

大規模なデータ セットの場合は、多くの時間を節約できますが、小さなデータ セットの場合は、余分なオーバーヘッドが発生しない可能性があります。同じタスクを完了するにはより多くのコードが必要ですが、大規模なデータ セットを扱っていない場合は、通常は価値がありません。

4.避免双重解释

当JavaScript代码想解析KavaScript的时候就会存在双重解释惩罚。当使用eval()函数或者是Function构造函数以及使用setTimeout()传一个字符串参数时都会发生这种情况。

//某些代码求值——避免!!
eval("alert(&#39;Hello world!&#39;)");

//创建新函数——避免!!
var sayHi = new Function("alert(&#39;Hello world!&#39;)");

//设置超时——避免!!
setTimeout("alert(&#39;Hello world!&#39;)", 500);
ログイン後にコピー

在以上这些例子中,都要解析包含了JavaScript代码的字符串。这个操作是不能在初始的解析过程中完成的,因为代码是包含在字符串中的,也就是说在JavaScript代码运行的同时必须新启动一个解析器来解析新的代码。实例化一个新的解析器有不容忽视的开销,所以这种代码要比直接解析慢得多。

//已修正
alert(&#39;Hello world!&#39;);

//创建新函数——已修正
var sayHi = function(){
    alert(&#39;Hello world!&#39;);
};

//设置一个超时——已修正
setTimeout(function(){
    alert(&#39;Hello world!&#39;);
}, 500);
ログイン後にコピー

如果要提高代码性能,尽可能避免出现需要按照JavaScript解析的字符串。

5.性能的其他注意事项

(1)原生方法较快

(2)Switch语句较快

(3)位运算符较快

最小化语句数

1.多个变量声明

//4个语句——很浪费
var count = 5;
var color = "blue";
var values = [1,2,3];
var now = new Date();

//一个语句
var count = 5,
    color = "blue",
    values = [1,2,3],
    now = new Date();
ログイン後にコピー

2.插入迭代值

当使用迭代值的时候,尽可能合并语句。

var name = values[i];
i++;
ログイン後にコピー

前面这2句语句各只有一个目的:第一个从values数组中获取值,然后存储在name中;第二个给变量i增加1.这两句可以通过迭代值插入第一个语句组合成一个语句。

var name = values[i++];
ログイン後にコピー

3.使用数组和对象字面量

//用4个语句创建和初始化数组——浪费
var values = new Array();
values[0] = 123;
values[1] = 456;
values[2] = 789;

//用4个语句创建和初始化对象——浪费
var person = new Object();
person.name = "Nicholas";
person.age = 29;
person.sayName = function(){
    alert(this.name);
};
ログイン後にコピー

这段代码中,只创建和初始化了一个数组和一个对象。各用了4个语句:一个调用构造函数,其他3个分配数据。其实可以很容易地转换成使用字面量的形式。

//只有一条语句创建和初始化数组
var values = [13,456,789];

//只有一条语句创建和初始化对象
var person = {
    name : "Nicholas",
    age : 29,
    sayName : function(){
        alert(this.name);
    }
};
ログイン後にコピー

重写后的代码只包含两条语句,减少了75%的语句量,在包含成千上万行JavaScript的代码库中,这些优化的价值更大。
只要有可能,尽量使用数组和对象的字面量表达方式来消除不必要的语句。

优化DOM交互

1.最小化现场更新

一旦你需要访问的DOM部分是已经显示的页面的一部分,那么你就是在进行一个现场更新。现场更新进行得越多,代码完成执行所花的事件就越长。

var list = document.getElementById(&#39;myList&#39;),
    item,
    i;
for (var i = 0; i < 10; i++) {
    item = document.createElement("li");
    list.appendChild(item);
    item.appendChild(document.createTextNode("Item" + i));
}
ログイン後にコピー

这段代码为列表添加了10个项目。添加每个项目时,都有2个现场更新:一个添加li元素,另一个给它添加文本节点。这样添加10个项目,这个操作总共要完成20个现场更新。

var list = document.getElementById(&#39;myList&#39;),
    fragment = document.createDocumentFragment(),
    item,
    i;
for (var i = 0; i < 10; i++) {
    item = document.createElement("li");
    fragment.appendChild(item);
    item.appendChild(document.createTextNode("Item" + i));
}
list.appendChild(fragment);
ログイン後にコピー

在这个例子中只有一次现场更新,它发生在所有项目都创建好之后。文档片段用作一个临时的占位符,放置新创建的项目。当给appendChild()传入文档片段时,只有片段中的子节点被添加到目标,片段本身不会被添加的。

一旦需要更新DOM,请考虑使用文档片段来构建DOM结构,然后再将其添加到现存的文档中。

2.使用innerHTML

有两种在页面上创建DOM节点的方法:使用诸如createElement()和appendChild()之类的DOM方法,以及使用innerHTML。对于小的DOM更改而言,两种方法效率都差不多。然而,对于大的DOM更改,使用innerHTML要比使用标准DOM方法创建同样的DOM结构快得多。

当把innerHTML设置为某个值时,后台会创建一个HTML解析器,然后使用内部的DOM调用来创建DOM结构,而非基于JavaScript的DOM调用。由于内部方法是编译好的而非解释执行的,所以执行快得多。

var list = document.getElementById("myList");
    html = "";
    i;

for (i=0; i < 10; i++){
    html += "<li>Item " + i +"</li>";
}
list.innerHTML = html;
ログイン後にコピー

使用innerHTML的关键在于(和其他的DOM操作一样)最小化调用它的次数。

var list = document.getElementById("myList");
    i;

for (i=0; i < 10; i++){
    list.innerHTML += "<li>Item " + i +"</li>";  //避免!!!
}
ログイン後にコピー

这段代码的问题在于每次循环都要调用innerHTML,这是极其低效的。调用innerHTML实际上就是一次现场更新。构建好一个字符串然后一次性调用innerHTML要比调用innerHTML多次快得多。

3.使用事件代理(根据第13章的概念,我认为此处应为“事件委托”更为妥当)

4.注意HTMLCollection

任何时候要访问HTMLCollection,不管它是一个属性还是一个方法,都是在文档上进行一个查询,这个查询开销很昂贵。

var images = document.getElementsByTagName("img"),
    image,
    i,len;

for (i=0, len=images.length; i < len; i++){
    image = images[i];
    //处理
}
ログイン後にコピー

将length和当前引用的images[i]存入变量,这样就可以最小化对他们的访问。发生以下情况时会返回HTMLCollection对象:

  • 进行了对getElementsByTagName()的调用;

  • 获取了元素的childNodes属性;

  • 获取了元素的attributes属性;

  • 访问了特殊的集合,如document.forms、document.images等。

 以上就是详细介绍JavaScript最佳实践 –性能的内容,更多相关内容请关注PHP中文网(www.php.cn)!

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Windows 10 と Windows 11 のパフォーマンス比較: どちらが優れていますか? Windows 10 と Windows 11 のパフォーマンス比較: どちらが優れていますか? Mar 28, 2024 am 09:00 AM

Windows 10 と Windows 11 のパフォーマンス比較: どちらが優れていますか?テクノロジーの継続的な開発と進歩により、オペレーティング システムは常に更新され、アップグレードされます。世界最大のオペレーティング システム開発者の 1 つとして、Microsoft の Windows シリーズ オペレーティング システムは常にユーザーから大きな注目を集めてきました。 2021 年、Microsoft は Windows 11 オペレーティング システムをリリースし、広範な議論と注目を引き起こしました。では、Windows 10 と Windows 11 のパフォーマンスの違いは何でしょうか?

Win11 と Win10 システムのパフォーマンスを比較すると、どちらの方が優れていますか? Win11 と Win10 システムのパフォーマンスを比較すると、どちらの方が優れていますか? Mar 27, 2024 pm 05:09 PM

Windows オペレーティング システムは、常にパーソナル コンピューターで最も広く使用されているオペレーティング システムの 1 つであり、最近 Microsoft が新しい Windows 11 システムを発売するまで、Windows 10 は長い間 Microsoft の主力オペレーティング システムでした。 Windows 11 システムのリリースに伴い、Windows 10 と Windows 11 システムのパフォーマンスの違いに関心が集まっていますが、どちらの方が優れているのでしょうか?まずはWを見てみましょう

Kirin 8000 プロセッサが Snapdragon シリーズと競合: 誰が王になれるでしょうか? Kirin 8000 プロセッサが Snapdragon シリーズと競合: 誰が王になれるでしょうか? Mar 25, 2024 am 09:03 AM

モバイルインターネットの時代において、スマートフォンは人々の日常生活に欠かせないものになりました。多くの場合、スマートフォンのパフォーマンスはユーザー エクスペリエンスの品質に直接影響します。スマートフォンの「頭脳」であるプロセッサーの性能は特に重要です。市場では、Qualcomm Snapdragon シリーズは常に強力なパフォーマンス、安定性、信頼性の代表格であり、最近では Huawei も独自の Kirin 8000 プロセッサを発売し、優れたパフォーマンスを備えていると言われています。一般ユーザーにとって、性能の良い携帯電話をいかに選ぶかは重要な課題となっている。今日はそうします

Embedding サービスのローカル実行パフォーマンスは OpenAI Text-Embedding-Ada-002 を上回っており、とても便利です。 Embedding サービスのローカル実行パフォーマンスは OpenAI Text-Embedding-Ada-002 を上回っており、とても便利です。 Apr 15, 2024 am 09:01 AM

Ollama は、Llama2、Mistral、Gemma などのオープンソース モデルをローカルで簡単に実行できるようにする非常に実用的なツールです。この記事では、Ollamaを使ってテキストをベクトル化する方法を紹介します。 Ollama をローカルにインストールしていない場合は、この記事を読んでください。この記事では、nomic-embed-text[2] モデルを使用します。これは、短いコンテキストおよび長いコンテキストのタスクにおいて OpenAI text-embedding-ada-002 および text-embedding-3-small よりも優れたパフォーマンスを発揮するテキスト エンコーダーです。 o が正常にインストールされたら、nomic-embed-text サービスを開始します。

PHP 言語と Go 言語の比較: 大きなパフォーマンスの違い PHP 言語と Go 言語の比較: 大きなパフォーマンスの違い Mar 26, 2024 am 10:48 AM

PHP と Go は一般的に使用される 2 つのプログラミング言語であり、それぞれに異なる特徴と利点があります。その中でも性能差は誰もが一般的に気にする問題です。この記事では、パフォーマンスの観点から PHP 言語と Go 言語を比較し、具体的なコード例を通じてパフォーマンスの違いを示します。まずは、PHPとGo言語の基本的な機能を簡単に紹介します。 PHP は、もともと Web 開発用に設計されたスクリプト言語で、学習と使用が簡単で、Web 開発の分野で広く使用されています。 Go 言語は、Google によって開発されたコンパイル言語です。

さまざまな Java フレームワークのパフォーマンスの比較 さまざまな Java フレームワークのパフォーマンスの比較 Jun 05, 2024 pm 07:14 PM

さまざまな Java フレームワークのパフォーマンス比較: REST API リクエスト処理: Vert.x が最高で、リクエスト レートは SpringBoot の 2 倍、Dropwizard の 3 倍です。データベース クエリ: SpringBoot の HibernateORM は Vert.x や Dropwizard の ORM よりも優れています。キャッシュ操作: Vert.x の Hazelcast クライアントは、SpringBoot や Dropwizard のキャッシュ メカニズムよりも優れています。適切なフレームワーク: アプリケーションの要件に応じて選択します。Vert.x は高パフォーマンスの Web サービスに適しており、SpringBoot はデータ集約型のアプリケーションに適しており、Dropwizard はマイクロサービス アーキテクチャに適しています。

PHP 配列キー値の反転: さまざまな方法のパフォーマンス比較分析 PHP 配列キー値の反転: さまざまな方法のパフォーマンス比較分析 May 03, 2024 pm 09:03 PM

PHP の配列キー値の反転メソッドのパフォーマンスを比較すると、array_flip() 関数は、大規模な配列 (100 万要素以上) では for ループよりもパフォーマンスが良く、所要時間が短いことがわかります。キー値を手動で反転する for ループ方式は、比較的長い時間がかかります。

C++ 関数はプログラムのパフォーマンスにどのような影響を与えますか? C++ 関数はプログラムのパフォーマンスにどのような影響を与えますか? Apr 12, 2024 am 09:39 AM

C++ プログラムのパフォーマンスに対する関数の影響には、関数呼び出しのオーバーヘッド、ローカル変数、およびオブジェクト割り当てのオーバーヘッドが含まれます。 関数呼び出しのオーバーヘッド: スタック フレーム割り当て、パラメーター転送、および制御転送が含まれます。これは、小規模な関数に大きな影響を与えます。ローカル変数とオブジェクト割り当てのオーバーヘッド: ローカル変数やオブジェクトの作成と破棄が大量に行われると、スタック オーバーフローやパフォーマンスの低下が発生する可能性があります。

See all articles