const, let 및 var의 v8 JavaScript 성능 영향?


88

기능적 차이에 관계없이 새 키워드 '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


예를 들어 let블록 범위에서 사용되는 것은 블록 범위 var가없고 함수 범위 만 있는보다 성능이 더 높아야한다고 생각 합니다.
adeneo

내가 물어 보면 왜 @adeneo입니까?
sean2078

1
@ sean2078-블록 범위에만있는 변수를 선언해야하는 경우 let그렇게 한 다음 가비지 수집되지만 var함수 범위 인은 반드시 같은 방식으로 작동하지 않습니다. 다시 한 번 말씀 드리지만, 용도에 따라 매우 구체적이어서 let와 둘 다 더 성능을 발휘할 const 있지만 항상 그런 것은 아닙니다.
adeneo

1
인용 된 코드가 var와 사이의 차이점을 보여주기 위해 어떻게 의미하는지 혼란 스럽 습니다. let전혀 사용하지 않습니다 let.
TJ Crowder

1
현재는 const 대 var .. 원래는 gist.github.com/srikumarks/1431640(srikumarks에 대한 크레딧)에서 제공되었지만 문제에 대한 코드를 가져 오라는 요청이있었습니다
sean2078

답변:


115

TL; DR

이론적 으로이 루프의 최적화되지 않은 버전 :

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 엔진은 루프를 충분히 내부 검사하여 그 차이를 최적화 할 수있는시기를 알 수 있습니다. (그 전에도 루프가 충분한 작업을 수행하여 추가 let관련 오버 헤드가 제거 될 가능성이 있습니다 .하지만 이제는 걱정할 필요가 없습니다.)

합성 벤치 마크 는 오류가 발생하기 매우 쉽기 때문에 주의 하고 실제 코드가하지 않는 방식 (좋은 방법과 나쁜 방법 모두)으로 JavaScript 엔진 최적화 프로그램을 트리거합니다. 그러나 종합적인 벤치 마크가 필요한 경우 다음 중 하나가 있습니다.

V8 / Chrome 또는 SpiderMonkey / Firefox에서 합성 테스트에 큰 차이가 없다고 말합니다. (두 브라우저에서 반복되는 테스트는 하나의 승리 또는 다른 하나의 승리가 있으며 두 경우 모두 오류 범위 내에서 발생합니다.) 그러나 다시 말하지만 이는 코드가 아니라 합성 벤치 마크입니다. 코드에 성능 문제가있는 경우 코드의 성능에 대해 걱정하십시오.

스타일 문제로, let클로저에서 루프 변수를 사용하면 범위 지정 이점과 클로저 인 루프 이점을 선호 합니다.

세부

루프 에서 var와 사이의 중요한 차이점은 각 반복마다 다른 것이 생성 된다는 것입니다 . 고전적인 "루프의 폐쇄"문제를 해결합니다.letfori

각 루프 본문 ( spec link )에 대한 새 EnvironmentRecord를 만드는 것은 작업이며 작업에는 시간이 걸리므로 이론적으로 let버전이 버전보다 느립니다 var.

그러나 i위의 실행 가능한 스 니펫 예제에서했던 것처럼를 사용하는 루프 내에서 함수 (클로저)를 만드는 경우에만 차이가 중요합니다 . 그렇지 않으면 구별을 관찰 할 수 없으며 최적화 할 수 있습니다.

여기 2018 년에는 V8 (및 Firefox의 SpiderMonkey)이의 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;
}

물론 해결해야 할 실제 문제가있는 경우에만 문제가되지 않으며 걱정해야 할 문제입니다.


답변 주셔서 감사합니다-동의합니다. 따라서 첫 번째 for 루프 예제에서 언급 한대로 반복 작업에 var 사용을 표준화했으며 성능 테스트가 보이는 것처럼 성능 차이가 본질적으로 존재하지 않는다고 가정하여 다른 모든 선언에 대해 let / const를 사용했습니다. 지금 표시합니다. 아마도 나중에 const에 대한 최적화가 추가 될 것입니다. 즉, 다른 사람이 코드 예제를 통해 눈에 띄는 차이를 보여줄 수없는 경우입니다.
sean2078

@ sean2078 : let루프 예제에서도 사용합니다. 99.999 %의 경우 성능 차이는 걱정할 가치가 없습니다.
TJ Crowder

2
2018 년 중반부터 let과 var가있는 버전은 Chrome에서 속도가 동일하므로 더 이상 차이가 없습니다.
Max

1
@DanM .: 좋은 소식입니다. 적어도 V8과 SpiderMonkey에서는 최적화가 따라 잡힌 것 같습니다. :-)
TJ Crowder

1
감사. 그럴 수 있지.
하이퍼

18

루프 선언에서 "LET"가 더 좋습니다.

네비게이터에서 다음과 같은 간단한 테스트 (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.5ms 이상입니다.

let을 사용한 루프 시간이 더 낫다는 것을 알았습니다.


6
Firefox 65.0에서 이것을 실행하면 평균 속도 var=138.8mslet=4ms. 즉, 오타가 아닌 let지금보다 30 배 배 빠른
카타 마리

6
방금 Node v12.5에서 시험해 보았습니다. 평균 속도는 var=2.6mslet=1.0ms입니다. 따라서 Node는 두 배 이상 빠릅니다.
Kane Hooper

2
옵티마이 저가있을 때 성능 테스트가 어렵다는 일반적인 요점을 만들기 위해 : let 루프가 완전히 최적화되고 있다고 생각합니다. 블록 내부에만 존재하고 루프는 부작용이 없으며 V8은 그것이 가능하다는 것을 알만큼 똑똑합니다. 블록을 제거한 다음 루프를 제거하십시오. var 선언이 올려 져서 알 수 없습니다. 루프는 1ms / 0.4ms이지만 둘 다 증가하는 루프 외부에 변수 j (var 또는 let)가 있으면 1ms / 1.5ms를 얻습니다. 즉, var 루프가 변경되지 않고 이제 루프가 더 오래 걸립니다.
Euan Smith

@KaneHooper-파이어 폭스에서 5 배 차이가 있다면, 그것을 한 빈 루프 본문이어야합니다. 실제 루프에는 빈 본문이 없습니다.
TJ Crowder

합성 벤치 마크 , 특히 본문이 비어있는 루프가있는 벤치 마크를주의하십시오 . 실제로 루프에서 무언가를한다면, 이 합성 벤치 마크 (다시 한 번 조심하세요! :-))는 큰 차이가 없음을 시사합니다. 나는 또한 내 대답에 하나를 추가하여 현장에 있습니다 (계속 사라지는 jsPerf 테스트와는 다릅니다. :-)). 반복 실행은 하나의 승리 또는 다른 승리를 보여줍니다. 확실히 결정적인 것은 없습니다.
TJ Crowder

8

TJ Crowder 의 대답은 너무 훌륭합니다.

여기에 다음이 추가되었습니다. "기존 var 선언을 const로 편집하는 데 드는 비용을 언제 가장 많이 얻을 수 있습니까?"

가장 큰 성능 향상은 "내 보낸"함수와 관련이 있다는 것을 알았습니다.

따라서 파일 A, B, R 및 Z가 앱을 통해 일반적으로 사용되는 파일 U의 "유틸리티"함수를 호출하는 경우 해당 유틸리티 함수를 "const"로 전환하면 const에 대한 상위 파일 참조가 약해질 수 있습니다. 성능이 향상되었습니다. 제게는 눈에 띄게 빠르지는 않은 것 같았지만 전체 메모리 소비는 완전히 모 놀리 식 프랑켄슈타인 앱의 경우 약 1-3 % 감소했습니다. 클라우드 또는 베어 메탈 서버에서 현금 가방을 사용하는 경우 이러한 var 선언 중 일부를 const로 업데이트하는 데 30 분을 소비하는 것이 좋은 이유가 될 수 있습니다.

나는 당신이 어떻게 const, var 및 let이 커버 아래에서 작동하는지 읽었다면 이미 위의 결론을 내렸을 것입니다. 그러나 당신이 그것을 "흘렀을 경우": D.

업데이트를 할 때 노드 v8.12.0에서 벤치마킹 한 것을 기억 해보면 내 앱은 ~ 240MB RAM의 유휴 소비량에서 ~ 233MB RAM으로 변경되었습니다.


2

TJ Crowder의 대답은 매우 좋지만 :

  1. 'let'은 코드를 더 강력하지 않고 더 읽기 쉽게 만들기 위해 만들어졌습니다.
  2. 이론적으로는 var보다 느릴 것입니다.
  3. 실제로 컴파일러는 완료되지 않은 프로그램을 완전히 (정적 분석) 해결할 수 없으므로 언젠가 최적화를 놓칠 수 있습니다.
  4. 어떤 경우에도 'let'을 사용하면 내부 검사를 위해 더 많은 CPU가 필요하며 Google v8이 파싱을 시작할 때 벤치를 시작해야합니다.
  5. 인트로 스펙 션이 실패하면 'let'은 V8 가비지 컬렉터를 강하게 밀고 해제 / 재사용하려면 더 많은 반복이 필요합니다. 또한 더 많은 RAM을 소비합니다. 벤치는 이러한 점을 고려해야합니다.
  6. Google Closure는 let in var를 변환합니다.

var와 let 사이의 성능 차이의 영향은 단일 기본 루프가 아닌 실제 전체 프로그램에서 볼 수 있습니다.

어쨌든, 필요하지 않은 곳에 let을 사용하면 코드의 가독성이 떨어집니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.