javascript - v8 JavaScript 对 const、let 和 var 的性能影响?

标签 javascript performance constants v8 let

无论功能差异如何,使用新关键字“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

最佳答案

TL;博士
理论上 ,此循环的未优化版本:

for (let i = 0; i < 500; ++i) {
    doSomethingWith(i);
}
可能比使用 var 的相同循环的未优化版本慢:
for (var i = 0; i < 500; ++i) {
    doSomethingWith(i);
}
因为一个 不同 i使用 let 为每次循环迭代创建变量,而只有一个 ivar .
反对那个 是事实var被提升所以它被声明在循环之外,而 let仅在循环内声明,这可能提供优化优势。
实践中 ,在 2018 年,现代 JavaScript 引擎对循环进行了足够的内省(introspection),以了解何时可以优化这种差异。 (即使在此之前,您的循环很可能已经做了足够多的工作,以至于额外的 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之间的重要区别和 letfor循环是不同的 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);

为每个循环体( spec link )创建新的 EnvironmentRecord 是工作,工作需要时间,这就是为什么在理论上 let版本比 var 慢版本。
但只有在使用 i 的循环中创建函数(闭包)时,差异才重要。 ,就像我在上面的可运行代码段示例中所做的那样。否则,无法观察到差异并且可以优化掉。
在 2018 年,看起来 V8(和 Firefox 中的 SpiderMonkey)正在做足够的内省(introspection),在不使用 let 的循环中没有性能成本。的每次迭代变量语义。见 this test .

在某些情况下,const很可能会提供一个优化机会var不会,尤其是对于全局变量。
全局变量的问题在于它是全局的。 任何 任何地方的代码都可以访问它。所以如果你用 var 声明一个变量如果您从不打算更改(并且永远不会更改您的代码),则引擎不能假设它永远不会因为稍后加载的代码或类似的结果而更改。
const ,但是,您明确告诉引擎该值不能更改¹。所以它可以自由地进行任何它想要的优化,包括发出一个文字而不是使用它的代码的变量引用,知道这些值不能改变。
¹ 请记住,对于对象,值是对对象的引用,而不是对象本身。所以与 const o = {} ,你可以改变对象的状态( o.answer = 42 ),但你不能让 o指向一个新对象(因为这需要更改它包含的对象引用)。

使用时 letconst在其他 var - 类似的情况,他们不太可能有不同的表现。无论您使用 var,此函数都应该具有完全相同的性能或 let ,例如:
function foo() {
    var i = 0;
    while (Math.random() < 0.5) {
        ++i;
    }
    return i;
}

当然,这一切都不重要,只有当有真正的问题需要解决时才需要担心。

关于javascript - v8 JavaScript 对 const、let 和 var 的性能影响?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40070631/

相关文章:

c - 算法复杂度与运行时间

java - 如何在java中生成Hexanacci数?

无法在 C 中为 "const char * const *my_array"赋值

C++ 为什么返回的 const 引用可以被修改?

javascript - 像 JQuery 一样将整个代码放在一起

javascript - Node.js:从 POST 请求中获取响应主体

javascript - SyntaxError : expected expression, 在运行 angularJs 和 Node 时得到 '<'

c++ - 为什么当我使用变量存储数值结果而不是重新计算时,C++ 程序运行速度变慢?

c++ - 访问 map 元素

javascript - 将新的 Google Analytics 代码写入外部文件