Подтвердить что ты не робот

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

4b9b3361

Ответ 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 ответ очень хороший, но:

  1. 'let' сделан, чтобы сделать код более читабельным, а не более мощным
  2. по теории пусть будет медленнее чем вар
  3. на практике компилятор не может полностью решить (статический анализ) незавершенную программу, поэтому когда-нибудь пропустит оптимизацию
  4. в любом случае использование 'let' потребует больше процессора для самоанализа, стенд должен быть запущен, когда google v8 начнет анализировать
  5. если интроспекция не удалась, "let" будет сильно давить на сборщик мусора V8, для освобождения/повторного использования потребуется больше итераций. это также будет потреблять больше оперативной памяти. скамья должна учитывать эти моменты
  6. Google Closure превратит впустую в...

Влияние разрыва в производительности между var и let можно увидеть в реальной полной программе, а не в одном базовом цикле.

В любом случае, использование let там, где вам не нужно, делает ваш код менее читабельным.