常量的V8 JavaScript性能的影响,让我们和var?

问题描述 投票:59回答:4

无论功能上的差异,并使用新的关键字“让”和“常量”对相对“变种”性能的任何概括或具体的影响?

运行程序后:

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 const v8 let
4个回答
82
投票

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相关的开销是无论如何淘汰了。但现在你甚至不必为此担心。)

细节

在一个varletfor之间的重要区别是,不同的是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(及SpiderMonkey的在Firefox)是做足够的自省,有是在一个循环,不使用let的可变每次迭代语义的性能没有影响。见this jsPerf test


在某些情况下,const可能提供优化的机遇var不会,尤其是对全局变量。

与全局变量的问题在于它的,那么,全球;任何代码可以在任何地方访问它。所以,如果你用声明说var你永远不打算改变(和从来没有在你的代码做修改)一个变量,发动机不能假设它永远不会改变的代码后或类似的加载结果。

随着const,但是,你要明确地告诉该值不能change¹发动机。因此,它是自由地做它想要的任何优化,包括发光文字,而不是使用它的变量引用代码,知道该值不能改变。

¹请记住,对象,该值是对对象的引用,而不是对象本身。因此,与const o = {},你可以改变物体(o.answer = 42)的状态,但你不能让o指向一个新的对象(因为这需要改变的对象引用它包含)。


当使用其他let样的情况constvar,他们不太可能有不同的表现。您是否使用varlet时,这个功能应该有完全一样的性能:

function foo() {
    var i = 0;
    while (Math.random() < 0.5) {
        ++i;
    }
    return i;
}

这一切,当然,不太可能的事情和东西担心只有当有来解决一个实际问题。


7
投票

“LET”在环DECLARATIONS BETTER

在这样的导航一个简单的测试(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.5毫秒更

我发现,循环时间,让我们更好。


5
投票

T.J.克罗德的答案是如此出色。

下面是一个加:“我什么时候会得到我的最大收益上编辑现有VAR声明为const?”

我发现,最性能提升了使用“导出”功能做。

因此,如果文件A,B,R,和Z呼吁在文件U A“效用”功能是通常通过应用程式使用,则切换该效用函数到“常量”和母文件参考到一个const可以EAK一些改进的性能。这似乎对我来说,这是没有可测量的速度更快,但减少了约1-3%,我非常单片科学怪人版应用程序的总体内存消耗。其中,如果你在云端或baremetal服务器支出的现金袋,可能是一个很好的理由花30分钟梳理和更新其中的一些变种声明为const。

我意识到,如果你在幕后读入如何常数,变量,让你的工作可能已经结束了以上......但如果你“瞥”在它:d。

从我的节点v8.12.0记得标杆,当我做了更新,我的应用程序从240MB的RAM〜233MB RAM的空闲〜消费去了。


1
投票

T.J.克罗德的回答是非常好的,但:

  1. “让”时,使代码更易读,而不是更强大
  2. 理论令会比慢变种
  3. 通过实践编译器不能完全解决(静态分析)未完成的程序,所以有时会错过优化
  4. 在使用“让”需要内省更多的CPU任何情况下,替补必须被启动时,谷歌的V8开始解析
  5. 如果内省失败'让我们将努力推动在V8垃圾收集器,它会需要更多的迭代免费/重用。它也将消耗更多的内存。板凳一定要把这些点考虑
  6. 谷歌关闭将改变让无功...

VAR,让之间的性能目瞪口呆的效果可以在现实生活中完整的程序,而不是单一的基本回路中可以看出。

总之,使用让您不就得了,让你的代码的可读性。

© www.soinside.com 2019 - 2024. All rights reserved.