v8 Влияние производительности JavaScript на const, let и var?
Независимо от функциональных различий, использует ли новые ключевые слова "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
Ответы
Ответ 1
TL; DR
Теоретически, неоптимизированная версия этого цикла:
for (let i = 0; i < 500; ++i) {
doSomethingWith(i);
}
будет медленнее, чем неоптимизированная версия того же цикла с var
:
for (var i = 0; i < 500; ++i) {
doSomethingWith(i);
}
потому что разные переменные i
создаются для каждой итерации цикла с помощью let
, тогда как существует только один i
с переменной var
.
На практике, здесь, в 2018 году, V8 достаточно интроспекции цикла, чтобы знать, когда он может оптимизировать эту разницу. (Даже до этого, скорее всего, ваш цикл выполнял достаточно работы, что дополнительные издержки let
-related все равно были смыты. Но теперь вам даже не нужно об этом беспокоиться.)
подробности
Важное различие между var
и let
в цикле for
заключается в том, что для каждой итерации создается разное i
; он решает классическую проблему "замыкания в цикле":
function usingVar() {
for (var i = 0; i < 3; ++i) {
setTimeout(function() {
console.log("var i: " + i);
}, 0);
}
}
function usingLet() {
for (let i = 0; i < 3; ++i) {
setTimeout(function() {
console.log("let i: " + i);
}, 0);
}
}
usingVar();
setTimeout(usingLet, 20);
Ответ 2
"ДАВАЙ" ЛУЧШЕ В ДЕКЛАРАЦИЯХ ПЕТЛИ
С помощью простого теста (5 раз) в навигаторе вот так:
// WITH VAR
console.time("var-time")
for(var i = 0; i < 500000; i++){}
console.timeEnd("var-time")
Среднее время выполнения составляет более 2,5 мс
// WITH LET
console.time("let-time")
for(let i = 0; i < 500000; i++){}
console.timeEnd("let-time")
Среднее время выполнения составляет более 1,5 мс
Я обнаружил, что время цикла с let лучше.
Ответ 3
Ответ TJ Crowder очень хорош.
Вот дополнение: "Когда я получу максимальную отдачу от редактирования существующих объявлений var в const?"
Я обнаружил, что наибольшее повышение производительности было связано с "экспортированными" функциями.
Поэтому, если файлы A, B, R и Z вызывают функцию "утилиты" в файле U, которая обычно используется в вашем приложении, переключение этой функции утилиты на "const" и указание ссылки на родительский файл на const некоторые улучшения производительности. Мне показалось, что это не было заметно быстрее, но общее потребление памяти было уменьшено примерно на 1-3% для моего чрезвычайно монолитного приложения Frankenstein-ed. Что, если вы тратите мешки с наличными в облаке или на своем сервере с открытым исходным кодом, может быть хорошей причиной, чтобы потратить 30 минут, чтобы прочесать и обновить некоторые из этих объявлений var для const.
Я понимаю, что если вы прочитали, как const, var и let работают под покровом, вы, вероятно, уже заключили вышеизложенное... но на тот случай, если вы "оглянулись" на это: D.
Из того, что я помню о тестировании на узле v8.12.0, когда я делал обновление, мое приложение перешло из режима ожидания в ~ 240 МБ ОЗУ в ~ 233 МБ.
Ответ 4
TJ Crowder ответ очень хороший, но:
- 'let' сделан, чтобы сделать код более читабельным, а не более мощным
- по теории пусть будет медленнее чем вар
- на практике компилятор не может полностью решить (статический анализ) незавершенную программу, поэтому когда-нибудь пропустит оптимизацию
- в любом случае использование 'let' потребует больше процессора для самоанализа, стенд должен быть запущен, когда google v8 начнет анализировать
- если интроспекция не удалась, "let" будет сильно давить на сборщик мусора V8, для освобождения/повторного использования потребуется больше итераций. это также будет потреблять больше оперативной памяти. скамья должна учитывать эти моменты
- Google Closure превратит впустую в...
Влияние разрыва в производительности между var и let можно увидеть в реальной полной программе, а не в одном базовом цикле.
В любом случае, использование let там, где вам не нужно, делает ваш код менее читабельным.