Независимо от функциональных различий, имеет ли использование новых ключевых слов 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
javascript
performance
constants
v8
let
sean2078
источник
источник
let
используемый в области блока должен быть более производительным, чем уvar
которого нет области блока, а только области действия.let
она сделает это, а затем будет собирать мусор, в то времяvar
как функция, ограниченная областью действия, не обязательно будет работать таким же образом. Опять же, я думаю, это настолько специфично для использования, что и то,let
и другоеconst
может быть более производительным, но не всегда.var
иlet
: онlet
вообще никогда не используется .Ответы:
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
.Аргументом против этого является тот факт, что
var
объект поднимается, поэтому он объявляется вне цикла, тогда какlet
объект объявляется только внутри цикла, что может дать преимущество оптимизации.На практике , здесь, в 2018 году, современные движки JavaScript достаточно глубоко анализируют цикл, чтобы знать, когда можно оптимизировать эту разницу. (Даже до этого момента, скорее всего, ваш цикл выполнял достаточно работы, чтобы дополнительные
let
накладные расходы все равно были смыты. Но теперь вам даже не нужно об этом беспокоиться.)Остерегайтесь синтетических тестов, поскольку в них очень легко ошибиться, и запускайте оптимизаторы движка JavaScript так, как это не работает в реальном коде (как хорошие, так и плохие). Однако, если вам нужен синтетический тест, вот он:
Показать фрагмент кода
const now = typeof performance === "object" && performance.now ? performance.now.bind(performance) : Date.now.bind(Date); const btn = document.getElementById("btn"); btn.addEventListener("click", function() { btn.disabled = true; runTest(); }); const maxTests = 100; const loopLimit = 50000000; const expectedX = 1249999975000000; function runTest(index = 1, results = {usingVar: 0, usingLet: 0}) { console.log(`Running Test #${index} of ${maxTests}`); setTimeout(() => { const varTime = usingVar(); const letTime = usingLet(); results.usingVar += varTime; results.usingLet += letTime; console.log(`Test ${index}: var = ${varTime}ms, let = ${letTime}ms`); ++index; if (index <= maxTests) { setTimeout(() => runTest(index, results), 0); } else { console.log(`Average time with var: ${(results.usingVar / maxTests).toFixed(2)}ms`); console.log(`Average time with let: ${(results.usingLet / maxTests).toFixed(2)}ms`); btn.disabled = false; } }, 0); } function usingVar() { const start = now(); let x = 0; for (var i = 0; i < loopLimit; i++) { x += i; } if (x !== expectedX) { throw new Error("Error in test"); } return now() - start; } function usingLet() { const start = now(); let x = 0; for (let i = 0; i < loopLimit; i++) { x += i; } if (x !== expectedX) { throw new Error("Error in test"); } return now() - start; }
<input id="btn" type="button" value="Start">
В нем говорится, что в этом синтетическом тесте нет существенной разницы ни в V8 / Chrome, ни в SpiderMonkey / Firefox. (Повторные тесты в обоих браузерах дают один выигрыш или другой выигрыш, причем в обоих случаях в пределах погрешности.) Но опять же, это синтетический тест, а не ваш код. Беспокойтесь о производительности вашего кода, когда и если ваш код имеет проблемы с производительностью.
Что касается стиля, я предпочитаю
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 для каждого тела цикла ( ссылка на спецификацию ) - это работа, и работа требует времени, поэтому теоретически
let
версия работает медленнее, чемvar
версия.Но разница имеет значение только в том случае, если вы создаете функцию (закрытие) внутри цикла, который использует
i
, как я сделал в приведенном выше примере исполняемого фрагмента. В противном случае различия не будут заметны и могут быть устранены.Здесь, в 2018 году, похоже, что V8 (и SpiderMonkey в Firefox) проводит достаточный самоанализ, чтобы не было затрат на производительность в цикле, который не использует
let
семантику переменной на итерацию. Смотрите этот тест .В некоторых случаях это
const
может предоставить возможность оптимизации,var
которая не подходит, особенно для глобальных переменных.Проблема с глобальной переменной в том, что она глобальна; любой код в любом месте может получить к нему доступ. Поэтому, если вы объявляете переменную, с
var
которой вы никогда не собираетесь изменять (и никогда не меняете в своем коде), движок не может предположить, что она никогда не изменится в результате кода, загруженного позже или аналогичного.С
const
, хотя вы явно сообщающие , что значение не может change¹. Таким образом, можно свободно выполнять любую оптимизацию, которую он хочет, включая создание литерала вместо ссылки на переменную для кода, использующего его, зная, что значения не могут быть изменены.¹ Помните, что для объектов значение - это ссылка на объект, а не на сам объект. Таким образом
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
в примере цикла. Разница в производительности не стоит беспокоиться в случае 99,999%.«ПУСТЬ» ЛУЧШЕ В ПЕТЛЕЙ ДЕКЛАРАЦИИ
С помощью простого теста (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 лучше.
источник
var=138.8ms
иlet=4ms
. Это не опечатка,let
это больше , чем 30x раз быстрее , прямо сейчасvar=2.6ms
иlet=1.0ms
. Так что пусть Node работает чуть более чем в два раза быстрее.Ответ TJ Crowder очень хорош.
Вот добавление: «Когда я получу максимальную отдачу от редактирования существующих объявлений var в const?»
Я обнаружил, что наибольший прирост производительности связан с «экспортируемыми» функциями.
Поэтому, если файлы A, B, R и Z вызывают служебную функцию в файле U, которая обычно используется в вашем приложении, переключение этой служебной функции на const и ссылка родительского файла на const может привести к из некоторой улучшенной производительности. Мне показалось, что это не намного быстрее, но общее потребление памяти уменьшилось примерно на 1-3% для моего в высшей степени монолитного приложения в стиле Франкенштейна. Что, если вы тратите кучу денег на облако или на свой голый сервер, может быть хорошей причиной потратить 30 минут на прочесывание и обновление некоторых из этих объявлений var до const.
Я понимаю, что если вы прочтете, как const, var и let работать под прикрытием, вы, вероятно, уже пришли к заключению выше ... но в случае, если вы "просмотрели" это: D.
Из того, что я помню о тестировании на узле v8.12.0, когда я делал обновление, мое приложение перешло с ~ 240 МБ ОЗУ в простоя на ~ 233 МБ ОЗУ.
источник
Ответ TJ Crowder очень хорош, но:
Эффект разрыва в производительности между var и let можно увидеть в реальной полной программе, а не в одном базовом цикле.
В любом случае, использование let там, где это необязательно, сделает ваш код менее читаемым.
источник