JavaScript では、できる限りグローバル変数ではなくローカル変数を使用する必要があります。この文は誰でも知っていますが、最初に言ったのは誰でしょうか。なぜこれを行うのでしょうか?これには何か根拠があるのでしょうか?これを行わないと、パフォーマンスにどの程度の損失が発生しますか?この記事では、これらの質問に対する答えを探り、変数の読み取りおよび書き込みのパフォーマンスにどのような要素が関係しているかを根本的に理解します。
【オリジナル】JavaScript変数のパフォーマンス
【著者】ニコラス・C・ザカス
[翻訳] JavaScript では、可能な限りローカル変数を使用する必要があるのはなぜですか?
[翻訳者] Mingda
以下は原文の翻訳です。
JavaScript のパフォーマンスを向上させる方法について、最もよく聞かれる提案は、グローバル変数の代わりにローカル変数を使用することです。これは、Web 開発で 9 年間働いてきた私にとって、一度も疑問に思ったことのないアドバイスであり、JavaScript のスコープと識別子解決 (識別子解決) メソッドの処理に基づいています。
まず、JavaScript では関数がオブジェクトとして組み込まれていることを明確にする必要があります。関数を作成するプロセスは、実際にはオブジェクトを作成するプロセスです。各関数オブジェクトには [[Scope]] と呼ばれる内部プロパティがあり、関数の作成時のスコープ情報が含まれています。実際、[[Scope]] 属性はオブジェクトのリスト (変数オブジェクト) に対応しており、リスト内のオブジェクトには関数内からアクセスできます。たとえば、グローバル関数 A を作成した場合、A の [[Scope]] 内部プロパティには 1 つのグローバル オブジェクト (Global Object) のみが含まれます。また、A に新しい関数 B を作成した場合、B の [[Scope] ] 属性には次のものが含まれます。 2 つのオブジェクトがあり、関数 A の Activation Object オブジェクトが前にあり、グローバル オブジェクト (Global Object) が後ろにあります。
関数が実行されると、実行可能オブジェクト (実行オブジェクト) が自動的に作成され、スコープ チェーン (スコープ チェーン) にバインドされます。スコープ チェーンは、識別子解決のための次の 2 つの手順を通じて確立されます。
1. まず、関数オブジェクト[[Scope]]の内部プロパティ内のオブジェクトをスコープチェーンに順番にコピーします。
2. 次に、関数が実行されると、このオブジェクト、パラメータ (引数)、およびローカル変数 (名前付きパラメータを含む) の定義が含まれる新しいアクティベーション オブジェクト オブジェクトが作成されます。 . ドメインチェーンの先頭。
JavaScript コードの実行中に識別子が見つかると、識別子の名前に基づいて実行コンテキスト (実行コンテキスト) のスコープ チェーン内で識別子が検索されます。スコープ チェーン内の最初のオブジェクト (関数のアクティブ化オブジェクト) から開始して、見つからない場合はスコープ チェーン内の次のオブジェクトを検索し、識別子の定義が見つかるまで同様に検索します。スコープ内の最後のオブジェクト (グローバル オブジェクト) が検索後に見つからない場合は、エラーがスローされ、変数が未定義であることをユーザーに通知します。これは、ECMA-262 標準で説明されている関数実行モデルと識別子解決 (Identifier Resolution) プロセスであり、ほとんどの JavaScript エンジンが実際にこの方法で実装されていることがわかります。 ECMA-262 はこの構造体の使用を義務付けているわけではなく、関数のこの部分についてのみ説明していることに注意してください。
識別子の解決プロセス (識別子解決) を理解すると、主に検索プロセスが大幅に短縮されるため、ローカル変数が他のスコープの変数よりも速く解決される理由が理解できます。しかし、どれくらい速くなるのでしょうか?この質問に答えるために、さまざまなスコープの深さで変数のパフォーマンスをテストする一連のテストをシミュレートしました。
最初のテストは、最も単純な値を変数に書き込むことです (ここではリテラル値 1 が使用されています)。結果は次の図に示されています。これは非常に興味深いものです。
この結果から、識別子の解析プロセスで深い検索が必要な場合、パフォーマンスの低下が発生し、識別子の深さが増加するにつれてパフォーマンスの低下の程度が増加することを理解するのは難しくありません。当然のことながら、Internet Explorer のパフォーマンスは最悪でした (ただし、公平を期すために言うと、IE 8 ではいくつかの改善がありました)。ここにはいくつかの例外があることに注意してください。Google Chrome と WebKit の最新の深夜バージョンは、変数へのアクセス時間が非常に安定しており、スコープの深さが増加しても増加しません。もちろん、これは彼らが使用している次世代 JavaScript エンジン、V8 と SquirrelFish によるものであるはずです。これらのエンジンはコードの実行時に最適化を実行しますが、これらの最適化により変数へのアクセスがこれまでより高速になっているのは明らかです。 Opera も好調で、IE、Firefox、現行バージョンの Safari よりははるかに高速でしたが、V8 や Squirrelfish ベースのブラウザよりは遅かったです。 Firefox 3.1 Beta 2 のパフォーマンスはちょっと意外ですが、ローカル変数の実行効率は非常に高いのですが、スコープ層の数が増えると効率が大幅に低下します。ここではデフォルト設定を使用していることに注意してください。これは、Firefox のトレース機能がオンになっていないことを意味します。
上記の結果は、変数に対して書き込み操作を行った場合に得られたものですが、実際に変数を読み込む場合に状況が変わるのか気になったので、次のテストを行いました。読み取り速度が書き込み速度よりわずかに速いことがわかりましたが、パフォーマンスの変化の傾向は一貫しています。
前回のテストと同様に、Internet Explorer と Firefox は依然として最も遅く、Opera は非常に目を引くパフォーマンスを示しました。同様に、Chrome と Webkit Midnight Edition の最新バージョンもスコープの深さとは関係のないパフォーマンス傾向を示しました。はい、Firefox 3.1 Beta 2 の可変アクセス時間には依然として深さによる奇妙なジャンプがあります。
テスト中に、Chrome がグローバル変数にアクセスするとさらにパフォーマンスが低下するという興味深い現象を発見しました。グローバル変数にアクセスする時間はスコープ レベルとは関係ありませんが、同じレベルのローカル変数にアクセスする時間より 50% 長くなります。
これら 2 つのテストは私たちにどのような啓発をもたらしてくれるでしょうか? 1 つ目は、可能な限りローカル変数を使用するという古い観点を検証することです。すべてのブラウザーで、ローカル変数へのアクセスは、グローバル変数を含むスコープ全体の変数へのアクセスよりも高速です。このテストを通じて得られる経験は次のとおりです。
* 関数で使用されているすべての変数を注意深く確認してください。現在のスコープで定義されておらず、複数回使用されている変数がある場合は、その変数を .html ファイルに保存する必要があります。ローカル変数。このローカル変数を使用して読み取りおよび書き込み操作を実行します。これは、スコープ外の変数の検索深さを 1 に減らすのに役立ちます。グローバル変数は常にスコープ チェーンの最後の位置で検索されるため、これはグローバル変数にとって特に重要です。
※with文の使用は避けてください。実行コンテキスト(Execution Context)のスコープチェーンを変更し、先頭にオブジェクト(Variable Object)を追加するためです。つまり、with の実行中に、実際のローカル変数がスコープ チェーンの 2 番目の位置に移動され、パフォーマンスの低下が発生します。
* コードの一部が確実に例外をスローすることが確実な場合は、try-catch の使用を避けてください。これは、catch ブランチが と同じスコープ チェーンで処理されるためです。ただし、try 分岐コードではパフォーマンスが低下することはないため、予期しないエラーを検出するには try-catch を使用することをお勧めします。
このトピックについてさらに詳しい議論が必要な場合は、先月の Mountain View JavaScript Meetup で私が簡単な講演を行いました。 SlideShare でスライドをダウンロードしたり、私の講演の 11 分あたりから始まるパーティーの完全なビデオを視聴したりできます。
翻訳者注:
この記事を読んで疑問がある場合は、次の 2 つの記事を読むことをお勧めします。
* 「JavaScript オブジェクト モデル - 実行モデル」Richie 著
※「ECMA-262 第 3 版」では、主に実行コンテキストである第 10 章を参照してください。この記事で言及されている用語については、そこで詳しく説明されています。
最後に、Nicholas 氏は、Mountain View JavaScript Meetup について言及しました。Meetup の Web サイトは、実際には、ファイアウォールをバイパスしてアクセスする必要があります。参加するアクティビティ。ふふ。