ホームページ > 記事 > ウェブフロントエンド > JavaScript 配列の進化とパフォーマンス分析の例
JavaScript を使用する前、私はすでに C、C++、C# に精通していました。多くの C/C++ 開発者と同様、私の JavaScript に対する第一印象は良いものではありませんでした。この記事では、主に JavaScript 配列の進化とパフォーマンス分析について紹介します。この記事では、メモリ、最適化、構文の違い、パフォーマンス、および最近の進化について詳しく説明します。困っている友達は参考にしていただければ幸いです。
配列が主な理由の 1 つです。 JavaScript 配列は連続的ではなく、ハッシュマップや辞書のように実装されます。これはちょっと B レベル言語のような気がします。配列の実装は単純に不適切です。それ以来、JavaScript とそれに対する私の理解は大きく変わりました。
JavaScript の配列が実際の配列ではない理由
JavaScript について話す前に、まず配列とは何かについて話しましょう。
配列は、値を保持するために使用されるメモリ位置の連続したシーケンスです。 「連続的」(または連続的)という強調に注目することが重要です。
上の図は、配列がメモリにどのように格納されるかを示しています。この配列は 4 つの要素を保持し、各要素は 4 バイトです。合計で 16 バイトのメモリ領域を占有します。
tinyInt arr[4]; を宣言すると、割り当てられるメモリ領域のアドレスは 1201 から始まります。 arr[2] を読み取る必要がある場合は、数学的計算を通じて arr[2] のアドレスを取得するだけで済みます。 1201 + (2 X 4) を計算するには、1209 から直接読み取りを開始するだけです。
JavaScript のデータはハッシュ マップであり、リンク リストなどのさまざまなデータ構造を使用して実装できます。したがって、JavaScript var arr = new Array(4) で配列を宣言すると、コンピューターは上記のような構造を生成します。プログラムが arr[2] を読み取る必要がある場合は、1201 から始まるアドレス指定をトラバースする必要があります。
上記の高速な JavaScript 配列と実際の配列の違い。明らかに、数学的計算はリンクされたリストを走査するよりも高速です。これは特に長い配列に当てはまります。
JavaScript 配列の進化
友達が買った 256MB メモリのコンピューターをとても羨ましがっていた日々を覚えていますか?現在、8 GB の RAM はどこにでもあります。
同様に、JavaScript 言語も大きく進化しました。 V8 や SpiderMonkey から TC39、そして Web ユーザーの増加に至るまで、多大な努力により JavaScript は世界クラスの必需品になりました。巨大なユーザーベースを獲得すると、パフォーマンスの向上は当然のことながら難しい要件になります。
実際、最新の JavaScript エンジンは、配列が同種である (すべての要素が同じ型である) 場合、配列に連続したメモリを割り当てます。優れたプログラマは、JIT (ジャストインタイム コンパイラ) が C コンパイラ スタイルの計算を使用して要素を読み取ることができるように、配列が同種であることを常に保証します。
ただし、別の型の要素を同種の配列に挿入したい場合、JIT は配列全体を分解し、古い方法で再作成します。
つまり、コードがそれほど悪くなければ、JavaScript の Array オブジェクトは舞台裏で真の配列のままであり、これは現代の JS 開発者にとって非常に重要です。
さらに、ES2015/ES6以降、アレイはさらに進化しました。 TC39 は型付き配列 (Typed Array) を導入することを決定したため、ArrayBuffer が導入されました。
ArrayBuffer は、自由に操作できる連続メモリを提供します。ただし、メモリを直接操作するのは依然として複雑すぎて低レベルです。したがって、ArrayBuffer を処理するビューがあります。すでにいくつかのビューが利用可能であり、将来的にはさらに多くのビューが追加される予定です。
var buffer = new ArrayBuffer(8); var view = new Int32Array(buffer); view[0] = 100;
高性能で効率的な型付き配列は、WebGL の後に導入されました。 WebGL ワーカーは、バイナリ データを効率的に処理する方法という大きなパフォーマンスの問題に直面します。あるいは、SharedArrayBuffer を使用して複数の Web Worker プロセス間でデータを共有し、パフォーマンスを向上させることもできます。
単純なハッシュ マップから SharedArrayBuffer になったのは、とても素晴らしいことですよね?
古いスタイルの配列 vs 型付き配列: パフォーマンス
JavaScript 配列の進化については以前に説明しましたが、ここで最新の配列がどの程度のメリットをもたらすかをテストしてみましょう。 Node.js 8.4.0 を使用して Mac で実行したマイクロテストの結果をいくつか示します。
古いスタイルの配列: 挿入
var LIMIT = 10000000; var arr = new Array(LIMIT); console.time("Array insertion time"); for (var i = 0; i < LIMIT; i++) { arr[i] = i; } console.timeEnd("Array insertion time");
所要時間: 55 ミリ秒
Typed Array:插入 var LIMIT = 10000000; var buffer = new ArrayBuffer(LIMIT * 4); var arr = new Int32Array(buffer); console.time("ArrayBuffer insertion time"); for (var i = 0; i < LIMIT; i++) { arr[i] = i; } console.timeEnd("ArrayBuffer insertion time");
所要時間: 52 ミリ秒
こすって、何が見えますか?古いスタイルの配列と ArrayBuffer のパフォーマンスは同等ですか?ダメダメダメ。前述したように、最新のコンパイラは、同じ要素型の従来の配列をメモリに連続した配列に内部的に変換できるほど賢いことを思い出してください。これはまさに最初の例の場合です。 new Array(LIMIT) の使用にもかかわらず、この配列は依然として最新の配列として存在します。
次に、最初の例を変更し、配列を異種配列 (要素の型が完全に一致していない) に変更して、パフォーマンスに違いがあるかどうかを確認します。
旧式数组:插入(异构) var LIMIT = 10000000; var arr = new Array(LIMIT); arr.push({a: 22}); console.time("Array insertion time"); for (var i = 0; i < LIMIT; i++) { arr[i] = i; } console.timeEnd("Array insertion time");
時間: 1207ms
変更は 3 行目で発生し、配列を異種型に変更するステートメントを追加します。コードの残りの部分は同じままです。パフォーマンスの違いが現れ、22 倍遅くなります。
古いスタイルの配列: 読み取り
var LIMIT = 10000000; var arr = new Array(LIMIT); arr.push({a: 22}); for (var i = 0; i < LIMIT; i++) { arr[i] = i; } var p; console.time("Array read time"); for (var i = 0; i < LIMIT; i++) { //arr[i] = i; p = arr[i]; } console.timeEnd("Array read time");
時間: 196ms
Typed Array:读取 var LIMIT = 10000000; var buffer = new ArrayBuffer(LIMIT * 4); var arr = new Int32Array(buffer); console.time("ArrayBuffer insertion time"); for (var i = 0; i < LIMIT; i++) { arr[i] = i; } console.time("ArrayBuffer read time"); for (var i = 0; i < LIMIT; i++) { var p = arr[i]; } console.timeEnd("ArrayBuffer read time");
時間: 27ms
結論
型付き配列の導入は、JavaScript の開発における大きな一歩です。 Int8Array、Uint8Array、Uint8ClampedArray、Int16Array、Uint16Array、Int32Array、Uint32Array、Float32Array、Float64Array、これらはネイティブ エンディアン (ネイティブと同じ) を使用する型付き配列ビューです。 DataView を使用してカスタム ビュー ウィンドウを作成することもできます。将来的には、ArrayBuffers を簡単に操作できる DataView ライブラリがさらに増えることを願っています。
JavaScript 配列の進化はとても素晴らしいです。現在では、メモリ割り当てが高速、効率的、堅牢で、十分にスマートになっています。
以上がJavaScript 配列の進化とパフォーマンス分析の例の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。