この記事の本来の目的は、いくつかの簡単なコーディングのヒントを使用して JavaScript コンパイラーの最適化プロセスを促進し、コードの効率を向上させる方法を紹介することです。特にガベージコレクションの速度が速いゲームでは、パフォーマンスが少し悪いとユーザーに白い画面が表示されます。
JavaScript では、関数を呼び出すときに動的パラメーターを渡すことができますが、単純な 2 パラメーター関数を例にとると、コンパイラーはパラメーターの型、パラメーターの数、戻り値の型が呼び出されるタイミングのみを決定できます。動的に解析すると時間がかかります。コンパイラーは当然、単相的に予測可能なデータ構造、パラメーター統計などを処理できるようにしたいと考えています。
function example(a, b) { // we expect a, b to be numeric console.log(++a * ++b); }; example(); // bad example(1); // still bad example("1", 2); // dammit meg example(1, 2); // good
定数を使用すると、コンパイラはコンパイル中に変数の値の置換を完了できます。
const a = 42; // we can easily unfold this const b = 1337 * 2; // we can resolve this expression const c = a + b; // still can be resolved const d = Math.random() * c; // we can only unfold 'c' // before unfolding a; b; c; d; // after unfolding // we can do this at compile time! 42; 2674; 2716; Math.random() * 2716;
JIT コンパイラは、最も多く実行されたコードの部分を見つけることができます。コードをより小さなチャンクに分割すると、コンパイラーがコンパイル時にこれらのチャンクをインライン形式に変換し、実行速度を向上させるのに役立ちます。
数値とブール値は、文字列などの他のプリミティブ型よりもパフォーマンスが優れているため、できるだけ使用してください。文字列型を使用すると、追加のガベージ コレクション コストが発生する可能性があります。
const ROBOT = 0; const HUMAN = 1; const SPIDER = 2; let E_TYPE = { Robot: ROBOT, Human: HUMAN, Spider: SPIDER }; // bad // avoid uncached strings in heavy tasks (or better in general) if (entity.type === "Robot") { } // good // the compiler can resolve member expressions // without much deepness pretty fast if (entity.type === E_TYPE.Robot) { } // perfect // right side of binary expression can even get unfold if (entity.type === ROBOT) { }
可能な限り == 演算子の代わりに === 厳密比較演算子を使用してください。厳密な比較演算子を使用すると、コンパイラーによる型推定と変換の実行を回避できるため、特定のパフォーマンスが向上します。
JavaScript の if ステートメントも非常に柔軟で、同様の値を if(a) then bla タイプの条件選択ステートメントに直接渡すことができます。ただし、この場合も前述の厳密比較演算子や緩比較演算子と同様に、コンパイラで複数のデータ型に変換して比較する必要があり、すぐに結果を得ることができません。もちろん、これは略語の使用に対する盲目的な反対ではありませんが、パフォーマンスを重視するシナリオでは、あらゆる詳細を最適化することをお勧めします:
let a = 2; // bad // abstracts to check in the worst case: // - is value equal to true // - is value greater than zero // - is value not null // - is value not NaN // .. if (a) { // if a is true, do something } // good if (a === 2) { // do sth } // same goes for functions function b() { return (!false); }; if (b()) { // get in here slow } if (b() === true) { // get in here fast // the compiler knows a specific value to compare with }
パラメーターを取得するために argument[index] メソッドを使用することは避けてください。そして、渡されたパラメータ変数の変更はできるだけ避けるようにしてください:
function mul(a, b) { return (arguments[0]*arguments[1]); // bad, very slow return (a*b); // good }; function test(a, b) { a = 5; // bad, dont modify argument identifiers let tmp = a; // good tmp *= 2; // we can now modify our fake 'a' };
以下にリストされているいくつかの文法的特徴は、最適化プロセスに影響します:
eval
with
try/catch
同時に、関数や関数内でのクロージャの宣言は避けてください。これにより、多数の操作でガベージ コレクション操作が過剰に発生する可能性があります。
オブジェクト インスタンスは通常、暗黙的なクラスを共有するため、インスタンスの未定義変数にアクセスしたりその値を設定したりすると、暗黙的なクラスが作成されます。
// our hidden class 'hc_0' class Vector { constructor(x, y) { // compiler finds and expects member declarations here this.x = x; this.y = y; } }; // both vector objects share hidden class 'hc_0' let vec1 = new Vector(0, 0); let vec2 = new Vector(2, 2); // bad, vec2 got hidden class 'hc_1' now vec2.z = 0; // good, compiler knows this member vec2.x = 1;
配列の長さの計算値を可能な限りキャッシュし、単一の型を可能な限り同じ配列に格納します。 for-in 構文を使用して配列を反復処理すると非常に時間がかかるため、使用しないでください。また、ループ内の continue ステートメントや Break ステートメントのパフォーマンスも良好なので、使用する際に心配する必要はありません。さらに、短い論理部分をできる限り独立した関数に分割すると、コンパイラの最適化がより容易になります。さらに、プレフィックス自動インクリメント式を使用すると、パフォーマンスが若干向上する可能性があります。 (i++ ではなく ++i)
let badarray = [1, true, 0]; // bad, dont mix types let array = [1, 0, 1]; // happy compiler // bad choice for (let key in array) { }; // better // but always try to cache the array size let i = 0; for (; i < array.length; ++i) { key = array[i]; }; // good let i = 0; let key = null; let length = array.length; for (; i < length; ++i) { key = array[i]; };
draeImage 関数は、最も高速な 2D Canvas API の 1 つですが、描画の便宜のためにすべてのパラメーターを省略すると、パフォーマンスの低下も増大することに注意する必要があります。
// bad ctx.drawImage( img, x, y ); // good ctx.drawImage( img, // clipping sx, sy, sw, sh, // actual stuff x, y, w, h ); // much hax // no subpixel rendering by passing integers ctx.drawImage( img, sx|0, sy|0, sw|0, sh|0, x|0, y|0, w|0, h|0 );
上記は、高性能 JavaScript の記述内容です。その他の関連コンテンツについては、PHP 中国語 Web サイト (m.sbmmt.com) をご覧ください。