ES6 템플릿 리터럴이 문자열 연결보다 빠릅니까?


82

ES6에서 문자열 연결 또는 템플릿 리터럴을 사용할 때 최신 브라우저에서 HTML 코드 생성이 눈에 띄게 빠르게 실행됩니까?

예를 들면 :

문자열 연결

"<body>"+
  "<article>"+
    "<time datetime='" + date.toISOString() +"'>"+ date +"</time>"+
  "</article>"+
"</body>"

템플릿 리터럴

`<body>
  <article>
    <time datetime='${ date.toISOString() }'>${ date }</time>
  </article>
</body>`

2
문자열 연결은 개선의 여지가 눈에 띄는만큼 느리지 않습니다. 콧수염 / 밑줄 / 핸들 바와 같은 인기있는 템플릿 도구는 연결 또는 템플릿 리터럴보다 수십에서 수백 배 느립니다.
dandavis 2015 년

1
이론적으로 말하면 (JS가 컴파일되지 않는 한) 자리 표시 자 존재 여부에 관계없이 '문자열'을 구문 분석해야하므로 템플릿 리터럴이 느려집니다. JS 엔진은 템플릿 리터럴을 한 번 구문 분석하여 후속 사용이 연결된 문자열만큼 빠릅니다. 즉, 유일한 차이점은 템플릿 리터럴을 한 번 구문 분석하는 데 필요한 시간입니다.
Precastic

물론 문자열 연결이 더 빠릅니다. 계속되는 구문 분석이 없습니다. 그것은 단지 문자열의 길이를 추가하는 것입니다. 그래도 템플릿 리터럴을 사용합니다.
Banjocat

결과가 결정적이지 않기 때문에이 질문을 종결하기로 결정했습니다. 1. 속도는 엔진에 따라 다릅니다. 최소한 크롬과 파이어 폭스 사이에 차이 있을 수 있습니다 . 2. 속도는 연결 / 템플릿이 사용되는 방식과 어떤 데이터에 따라 달라집니다. 3. 동일한 엔진의 다른 버전간에 변경 될 수 있습니다. 4. Microbenchmarking은 잘못된 결과를 생성 할 수 있습니다. 5. 속도 차이는 무시해도 될 정도입니다. 글을 쓰는 시점에서 그것은 입니다 .
VLAZ

답변:


86

순간 문자열 연결이 더 빠른 것 같습니다 : http://jsperf.com/es6-string-literals-vs-string-concatenation

ES6 with variable                     19,992,512    ±5.21%    78% slower
String concatenation with variable    89,791,408    ±2.15%    fastest
ES6 with function                     461,358       ±3.12%    99% slower
String concatenation with function    503,255       ±1.77%    99% slower

나는 #enable-javascript-harmony플래그가 활성화 된 V8 4.3.31을 사용하는 Chrome 43.0.2334.0 카나리아 (64 비트)에서 실행되었습니다 .

참고로 Node.js의 최신 버전 (작성 당시 0.12.0)은 V8 3.28.73을 사용하고 있습니다 : https://raw.githubusercontent.com/joyent/node/master/ChangeLog

적용 할 수있는 가능한 모든 성능 최적화가 아직 적용되지 않았을 것이므로 ES6가 최종화에 가까워지고 이러한 기능이 안정 브랜치로 마이그레이션됨에 따라 성능이 향상 될 것으로 기대하는 것이 합리적입니다.


편집 : @ user1329482, @ icl7126, Nicolai Borisik 및 FesterCluck의 의견에 감사드립니다. 이 질문을받은 지 약 2 년이 지났으므로 ES6 브라우저 지원이 크게 증가했으며 상당한 성능 최적화가 이루어졌습니다. 다음은 몇 가지 업데이트 입니다.

편집 : (2020 년 2 월) @ JorgeFuentesGonzález 댓글 및 후속 확인을 기반으로 Chrome 결과가 업데이트되었습니다 .

Chrome (59.0.3035 기준)에서 ES6 문자열 리터럴이 더 빠릅니다 .

ES6 with variable                     48,161,401       ±1.07%    fastest
String concatenation with variable    27,046,298       ±0.48%    44% slower
ES6 with function                     820,441          ±1.10%    98% slower
String concatenation with function    807,088          ±1.08%    98% slower

업데이트 : Chrome (79.0.3945 기준)에서 문자열 연결이 더 빠릅니다 . 주석을 참조하십시오.

Firefox (57.0.0 기준)에서는 ES6 문자열 리터럴이 더 빠릅니다 .

ES6 with variable                     1,924,610,984    ±0.50%    fastest
String concatenation with variable    1,876,993,458    ±0.79%    3% slower
ES6 with function                     539,762          ±5.04%    100% slower
String concatenation with function    546,030          ±5.88%    100% slower

Safari (11.0.2 기준)에서는 다음 사항에 따라 다릅니다.

ES6 with variable                     1,382,752,744    ±0.71%    fastest
String concatenation with variable    1,355,512,037    ±0.70%    2% slower
ES6 with function                     876,516          ±1.01%    100% slower
String concatenation with function    883,370          ±0.79%    100% slower

타입 캐스트 문자열을 사용할 때 ES6 문자열 리터럴이 더 빠릅니다 . 그러나 리터럴에서 함수를 호출 할 때이 예제 에서는 문자열 연결이 더 빠릅니다 .

정말로 깊이 들어가서 Safari의 모든 성능 저하를 짜 내야한다면 문자 그대로 효과 성능 내에서 변수와 여러 참조를 잘못 입력했는지 여부를 확인하는 테스트를 설정하는 것이 좋습니다.


4
Firefox 50 64 비트-ES6는 연결 1,423,816,207 Ops / s와 속도가 같습니다.
icl7126 16.04.04

4
34 %에 대한 ES6 보간 빠른 연결보다는 사파리 9.0 크롬 55 여전히 ES6 보간 훨씬 느린 파이어 폭스 (50)와 동일한 속도
니콜라이 Borisik

1
템플릿 문자열은 이제 문자열 연결보다 훨씬 빠릅니다. 주어진 jsperf 버전 14를 참조하십시오. 기능 측면을 유지하면서 기술적으로 얻을 수있는 가장 정확하고 편향되지 않은 것입니다. 버전 17은 편향이 거의 없지만 비현실적입니다.
FesterCluck

1
"개정 1"문자열 리터럴에서 당신이 전달 된 jsperf 링크는 최신 크롬에서 문자열 연결보다 여전히 느립니다 u.teknik.io/nPmY8.png
호르헤 푸엔테스 곤잘레스

1
jsperf 결과 파일이 삭제되었습니다. 만료없이 업로드 : u.teknik.io/02OVr.png
Jorge Fuentes González

7

node.js v6.0.0 에서 순진한 테스트를 했고 거의 동일한 성능을 얻었 습니다 . 테스트가 너무 순진하기 때문에 숫자를 너무 많이 믿지 마십시오. 그러나 오늘날 JIT 컴파일러는 매우 최적화 된 코드를 생성하는 것 같습니다. 이를 통해 노드 앱에 대한 연결보다 템플릿을 선호하도록 결정할 수 있습니다.

참고로 이것은 내가 사용한 코드입니다.

'use strict'

function strConcat(i) {
    return 'abc' + i + 'def'
}

function strTemplate(i) {
    return `abc${i}def`
}

function run(strategy) {
    let before = new Date().getTime()
    let len = 0
    for ( let i = 0; i < 10000000; i+=1 ) {
        len += strategy(i).length
    }
    console.log(len + ' - ' + ((new Date().getTime()) - before) + 'ms')
}

console.log('strConcat')
run(strConcat)

console.log('strTemplate')
run(strTemplate)

결과는 다음과 같습니다.

strConcat
128888890 - 1904ms
strTemplate
128888890 - 1979ms

저는 len옵티마이 저가 전체 루프를 최적화하지 않도록 절대적으로 확인했습니다. 어쨌든 여전히 매우 간단한 테스트입니다. 누군가가 더 정교한 것을 만들 수있을 것입니다.


1
비슷한 벤치 마크를 실행했는데 비슷한 결과를 얻었습니다. 내 벤치 마크에는 더 많은 문자열이 포함되었으며 그중 일부는 더 길었습니다. 보간은 연결보다 약간 더 잘 수행됩니다.
rattray

2

난수를 문자열로 사용하는 간단한 테스트의 경우 둘 다 Chrome 및 FF에서 매우 가깝습니다.

Chrome 58.0.3029 / Windows 10에서 테스트

문자열 리터럴 2,996,883 ± 2.36 % 가장 빠름

연산자 (+) 3,054,078 ± 2.01 % 가장 빠름

Concat 함수 2,659,391 ± 2.35 % 13 % 느림

Firefox 53.0.2 / Windows 10에서 테스트

문자열 리터럴 1,923,835 ± 1.52 % 가장 빠름

연산자 (+) 1,948,503 ± 1.13 % 가장 빠름

Concat 기능 1,810,857 ± 1.81 % 8 % 느림

여기 jsperf에서 테스트


1

TL; DR

연결 속도와 관련하여 더 빠르고 일관성이 있습니다. 그러나 변수 1 개 또는 2 개의 차이는 거의 없습니다 (1 억 호출의 경우 .3 초 미만).

편집하다

두 번째 실행 후 연결이 대부분 두 가지 중 더 빠른 것 같습니다.


그래서 저는 더 광범위하고 두 기능의 확장 성을 (조금) 살펴본 테스트를 제공하여 analog-nico의 답변 을 확장하고 싶었습니다 .

pastebin의 코드

각 함수에 대해 4 개의 테스트 케이스를 사용하기로 결정했습니다. 변수는 앞쪽에, 끝에 하나, 중간에 하나, 중간에 두 개 있습니다. 기본 설정은 동일합니다. 저는 함수의 100,000,000 반복을 사용하고 있으며 이러한 반복은 100 번 실행됩니다. 최적화를 방지하기 위해 동일한 메커니즘을 사용했습니다. 즉, 결과 문자열의 길이 합계를 가져와 로깅했습니다. 또한 필요한 시간을 기록했지만 (얼마나 걸릴지 추측하기 위해) 배열에 저장했습니다.

그 후 각 방법의 평균, 최소, 최대 및 표준 편차를 계산했습니다.

결과는 다음과 같습니다.

{ 
  sum: { 
    t: { 
      start: 2072751, 
      mid: 2338476, 
      end: 2083695, 
      double: 2950287 
    },
    c: { 
      start: 2086059, 
      mid: 2345551, 
      end: 2074732, 
      double: 2922929 
    } 
  },
  avg: { 
    t: { 
      start: 20727.51,
      mid: 23384.76,
      end: 20836.95,
      double: 29502.87 
    },
    c: { 
      start: 20860.59,
      mid: 23455.51,
      end: 20747.32,
      double: 29229.29 
    } 
  },
  sd: {
    t: {
      start: 335.6251329981114,
      mid: 282.9490809315344,
      end: 286.2220947096852,
      double: 216.40844045461824 
    },
    c: {
      start: 255.4803356424913,
      mid: 221.48744862858484,
      end: 238.98242111084238,
      double: 209.9309074433776 
    } 
  },
  min: { 
    t: { 
      start: 20490, 
      mid: 23216, 
      end: 20588, 
      double: 29271 
    },
    c: { 
      start: 20660, 
      mid: 23258, 
      end: 20534, 
      double: 28985 
    } 
  },
  max: { 
    t: { 
      start: 23279, 
      mid: 25616, 
      end: 22887, 
      double: 30843 
    },
    c: { 
      start: 22603, 
      mid: 25062, 
      end: 22403, 
      double: 30536 
    } 
  } 
}

t-objects의 값은 템플릿 용이고 c-objects의 값은 연결 용입니다. start변수가 시작 부분에 있고 중간에 있음을 의미하고 중간에 있음을 의미하며 끝이 끝에 있음을 의미하며 두 개의 변수가 있음을 의미합니다. sum100 회 실행의 합계입니다. avg평균 실행입니다 sum / 100. sd 여기에 쉬운 방법, wikipedia (simple english)가 있습니다. min그리고 max각각 실행의 최소 및 최대 값입니다.

결과

평균이 낮고 최소값이 낮다는 점을 고려할 때 문자열 끝에 위치하지 않는 단일 변수의 경우 템플릿이 더 빠른 것 같습니다. 문자열 끝에 변수를 넣거나 문자열에 여러 변수가 있으면 연결이 더 빠릅니다.

템플릿의 최소값과 평균이 처음 두 조건과 관련하여 연결 상대보다 좋지만 표준 편차는 지속적으로 더 나쁩니다. 변수가 많을수록 차이가 줄어드는 것 같습니다 (더 많은 테스트가 필요함).

대부분의 템플릿은 문자열에서 하나의 변수에만 사용되지 않을 것이므로 연결을 고수하면 더 나은 성능을 얻을 수 있습니다. 그러나 그 차이는 (적어도 현재로서는) 매우 미미합니다. 두 변수를 사용한 100,000,000 (1 억) 평가에서 차이는 약 1/4 초인 273,58ms에 불과합니다.


두 번째 실행

두 번째 실행은 다소 다르게 보입니다. 최대 값, 평균 절대 편차 및 표준 편차를 제외하고 모든 측정은 연결이 템플릿보다 빠르다는 것을 증명했습니다.

언급 된 세 가지 측정 값은 변수가 문자열 끝에 있거나 문자열에 두 개의 변수가있을 때 템플릿에 대해 더 낮은 값을 가졌습니다.

결과는 다음과 같습니다.

{
  "sum": {
    "t": {
      "start": 1785103,
      "mid": 1826679,
      "end": 1719594,
      "double": 2110823,
      "many": 4153368
    },
    "c": {
      "start": 1720260,
      "mid": 1799579,
      "end": 1716883,
      "double": 2097473,
      "many": 3836265
    }
  },
  "avg": {
    "t": {
      "start": 17851.03,
      "mid": 18266.79,
      "end": 17195.94,
      "double": 21108.23,
      "many": 41533.68
    },
    "c": {
      "start": 17202.6,
      "mid": 17995.79,
      "end": 17168.83,
      "double": 20974.73,
      "many": 38362.65
    }
  },
  "sd": {
    "t": {
      "start": 858.7857061572462,
      "mid": 886.0941856823124,
      "end": 786.5366719994689,
      "double": 905.5376950188214,
      "many": 1744.9005638144542
    },
    "c": {
      "start": 599.0468429096342,
      "mid": 719.1084521127534,
      "end": 935.9367719563112,
      "double": 991.5642274204934,
      "many": 1465.1116774840066
    }
  },
  "aad": {
    "t": {
      "start": 579.1207999999996,
      "mid": 576.5628000000003,
      "end": 526.8268,
      "double": 586.9651999999998,
      "many": 1135.9432000000002
    },
    "c": {
      "start": 467.96399999999966,
      "mid": 443.09220000000016,
      "end": 551.1318000000008,
      "double": 610.2321999999999,
      "many": 1020.1310000000003
    }
  },
  "min": {
    "t": {
      "start": 16932,
      "mid": 17238,
      "end": 16387,
      "double": 20016,
      "many": 39327
    },
    "c": {
      "start": 16477,
      "mid": 17137,
      "end": 16226,
      "double": 19863,
      "many": 36424
    }
  },
  "max": {
    "t": {
      "start": 23310,
      "mid": 24102,
      "end": 21258,
      "double": 26883,
      "many": 49103
    },
    "c": {
      "start": 19328,
      "mid": 23203,
      "end": 22859,
      "double": 26875,
      "many": 44352
    }
  },
  "median": {
    "t": {
      "start": 17571,
      "mid": 18062,
      "end": 16974,
      "double": 20874,
      "many": 41171.5
    },
    "c": {
      "start": 16893.5,
      "mid": 18213,
      "end": 17016.5,
      "double": 20771,
      "many": 38849
    }
  }
}

코드는 여기에 있습니다


현재 테스트 스크립트의 새 버전을 실행하고 있습니다. 여기에는 absolute average meanmedian. 또한 교체 할 10 개의 변수로 런타임을 벤치마킹합니다.
Armin

0

위의 벤치 마크는 유용하지 않다고 생각합니다. 보간 또는 연결의 결과가 사용되지 않았습니다. 예, 연결이 매우 빠릅니다. 거기에 문자열을 처리하지 않고 결과 문자열에 상위 문자열에 대한 링크 만 있기 때문입니다. 그러나 결과 문자열을 시도하거나 다른 문자열과 비교하면 문자열이 평면 문자열로 직렬화되며 시간이 좀 걸립니다. 따라서 보간은 CPU 및 메모리 사용량에 더 효과적 일 수 있으며 실제 경우에는 연결이 가능합니다.

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