機能の違いに関係なく、新しいキーワード「let」と「const」を使用すると、「var」に比べてパフォーマンスに一般的または特定の影響がありますか?
プログラムを実行した後:
function timeit(f, N, S) {
var start, timeTaken;
var stats = {min: 1e50, max: 0, N: 0, sum: 0, sqsum: 0};
var i;
for (i = 0; i < S; ++i) {
start = Date.now();
f(N);
timeTaken = Date.now() - start;
stats.min = Math.min(timeTaken, stats.min);
stats.max = Math.max(timeTaken, stats.max);
stats.sum += timeTaken;
stats.sqsum += timeTaken * timeTaken;
stats.N++
}
var mean = stats.sum / stats.N;
var sqmean = stats.sqsum / stats.N;
return {min: stats.min, max: stats.max, mean: mean, spread: Math.sqrt(sqmean - mean * mean)};
}
var variable1 = 10;
var variable2 = 10;
var variable3 = 10;
var variable4 = 10;
var variable5 = 10;
var variable6 = 10;
var variable7 = 10;
var variable8 = 10;
var variable9 = 10;
var variable10 = 10;
function varAccess(N) {
var i, sum;
for (i = 0; i < N; ++i) {
sum += variable1;
sum += variable2;
sum += variable3;
sum += variable4;
sum += variable5;
sum += variable6;
sum += variable7;
sum += variable8;
sum += variable9;
sum += variable10;
}
return sum;
}
const constant1 = 10;
const constant2 = 10;
const constant3 = 10;
const constant4 = 10;
const constant5 = 10;
const constant6 = 10;
const constant7 = 10;
const constant8 = 10;
const constant9 = 10;
const constant10 = 10;
function constAccess(N) {
var i, sum;
for (i = 0; i < N; ++i) {
sum += constant1;
sum += constant2;
sum += constant3;
sum += constant4;
sum += constant5;
sum += constant6;
sum += constant7;
sum += constant8;
sum += constant9;
sum += constant10;
}
return sum;
}
function control(N) {
var i, sum;
for (i = 0; i < N; ++i) {
sum += 10;
sum += 10;
sum += 10;
sum += 10;
sum += 10;
sum += 10;
sum += 10;
sum += 10;
sum += 10;
sum += 10;
}
return sum;
}
console.log("ctl = " + JSON.stringify(timeit(control, 10000000, 50)));
console.log("con = " + JSON.stringify(timeit(constAccess, 10000000, 50)));
console.log("var = " + JSON.stringify(timeit(varAccess, 10000000, 50)));
..私の結果は次のとおりです。
ctl = {"min":101,"max":117,"mean":108.34,"spread":4.145407097016924}
con = {"min":107,"max":572,"mean":435.7,"spread":169.4998820058587}
var = {"min":103,"max":608,"mean":439.82,"spread":176.44417700791374}
ただし、ここで説明する議論は、特定のシナリオでのパフォーマンスの違いの本当の可能性を示しているようです: https://esdiscuss.org/topic/performance-concern-with-let-const
理論上、このループの最適化されていないバージョン:
for (let i = 0; i < 500; ++i) {
doSomethingWith(i);
}
var
を使用した同じループの最適化されていないバージョンよりも遅くなります。
for (var i = 0; i < 500; ++i) {
doSomethingWith(i);
}
differenti
変数は、let
を使用するループの反復ごとに作成されるのに対し、i
を使用するvar
は1つしかないためです。
実際には、ここ2018年に、V8はループの内省を十分に行い、その差をいつ最適化できるかを知ります。 (それ以前でも、ループが十分な処理を行っていたため、追加のlet
関連のオーバーヘッドが洗い流された可能性があります。しかし、今では心配する必要さえありません。)
var
ループのlet
とfor
の重要な違いは、反復ごとに異なるi
が作成されることです。従来の「ループ内のクロージャ」問題に対処します。
function usingVar() {
for (var i = 0; i < 3; ++i) {
setTimeout(function() {
console.log("var's i: " + i);
}, 0);
}
}
function usingLet() {
for (let i = 0; i < 3; ++i) {
setTimeout(function() {
console.log("let's i: " + i);
}, 0);
}
}
usingVar();
setTimeout(usingLet, 20);
ループ本体ごとに新しいEnvironmentRecordを作成する( spec link )作業が必要であり、作業に時間がかかるため、理論的にはlet
バージョンがvar
バージョンよりも遅いのはこのためです。
ただし、上記の実行可能なスニペットの例で行ったように、i
を使用するループ内で関数(クロージャー)を作成する場合にのみ、違いは重要です。それ以外の場合、区別は観察できず、最適化して削除できます。
ここ2018年、V8(およびFirefoxのSpiderMonkey)は、let
の変数ごとのセマンティクスを使用しないループでパフォーマンスコストがないことを十分に内省しているようです。 this jsPerf test を参照してください。
場合によっては、const
は、var
にはない最適化の機会を、特にグローバル変数には提供する可能性があります。
グローバル変数の問題は、それがグローバルであることです。 anyコードanywhereはアクセスできます。したがって、var
で変数を宣言する場合、決して変更するつもりはない(そしてコードを変更しない)場合、エンジンは、後でロードされるコードまたは同様のコードの結果として、変数が決して変更されないことを想定できません。
ただし、const
を使用すると、値を変更できないことをエンジンに明示的に伝えます¹。したがって、値を変更できないことを認識して、それを使用するコードへの変数参照の代わりにリテラルを発行するなど、必要な最適化を自由に行うことができます。
¹オブジェクトの場合、値はaであることに注意してくださいオブジェクト自体ではなく、オブジェクトを参照してください。したがって、const o = {}
を使用すると、オブジェクトの状態を変更できます(o.answer = 42
)が、o
が新しいオブジェクトを指すようにすることはできません(含まれるオブジェクト参照を変更する必要があるため)。
let
またはconst
を他のvar
のような状況で使用する場合、パフォーマンスが異なる可能性はほとんどありません。この関数は、var
を使用する場合でもlet
を使用する場合でも、まったく同じパフォーマンスを持つ必要があります。たとえば、
function foo() {
var i = 0;
while (Math.random() < 0.5) {
++i;
}
return i;
}
もちろん、すべてが問題になる可能性は低く、解決すべき実際の問題がある場合にのみ心配する必要があります。
"LET" ISループ宣言でより良い
そのようなナビゲータでの簡単なテスト(5回)で:
// WITH VAR
console.time("var-time")
for(var i = 0; i < 500000; i++){}
console.timeEnd("var-time")
平均実行時間は2.5ms以上です
// WITH LET
console.time("let-time")
for(let i = 0; i < 500000; i++){}
console.timeEnd("let-time")
平均実行時間は1.5ms以上です
Letを使用したループ時間の方が優れていることがわかりました。
T.J。Crowderの答えはとても素晴らしいです。
「既存のvar宣言をconstに編集することで、いつまでに最大限の価値を得ることができますか?」
パフォーマンスの最大の向上は、「エクスポートされた」関数に関係していることがわかりました。
したがって、ファイルA、B、R、およびZが、アプリで一般的に使用されるファイルUの「ユーティリティ」関数を呼び出し、そのユーティリティ関数を「const」に切り替え、constへの親ファイル参照がeakできる場合いくつかの改善されたパフォーマンス。かなり高速ではないように思えましたが、全体的なメモリ消費は、私の非常にモノリシックなFrankenstein版のアプリで約1〜3%削減されました。クラウドまたはベアメタルサーバーに大量の現金を費やしている場合、これらのvar宣言の一部を調べてconstに更新するのに30分を費やすのが妥当な理由になります。
Const、var、およびカバーの下で作業する方法を読んでいると、おそらく上記をすでに完了していることがわかります...しかし、あなたがそれを見た場合:D。
更新を行っていたときのノードv8.12.0でのベンチマークの記憶から、私のアプリはアイドル消費が最大240MB RAMから最大233MB RAMになりました。
T.J.クラウダーの答えは非常に良いですが、
Varとletのパフォーマンスのギャップの影響は、単一の基本的なループではなく、実際の完全なプログラムで見ることができます。
とにかく、必要のないところでletを使用すると、コードが読みにくくなります。