[javascript] JavaScript에서 배열을 반복하는 가장 빠른 방법은 무엇입니까?

나는 당신이 다음과 같이 루프를 작성해야한다는 책에서 배웠습니다.

for(var i=0, len=arr.length; i < len; i++){
    // blah blah
}

그래서 arr.length매번 계산되지 않습니다.

다른 사람들은 컴파일러가 이것에 대해 약간의 최적화를 할 것이라고 말합니다.

for(var i=0; i < arr.length; i++){
    // blah blah
}

실제로 어떤 방법이 가장 좋은지 알고 싶습니다.



답변

대부분의 최신 브라우저에서이 테스트를 수행 한 후 …

http://jsben.ch/dyM52

현재 가장 빠른 형태의 루프 (그리고 내 의견으로는 가장 문법적으로 명백합니다).

길이 캐싱이있는 루프의 표준

for (var i = 0, len = myArray.length; i < len; i++) {

}

나는 이것이 JavaScript 엔진 개발자들에게 박수를 보내는 경우라고 분명히 말할 것입니다. 런 시간에 최적화되어야한다 명확성 , 하지 영리함 .


답변

자바 스크립트 배열을 반복하는 가장 빠른 방법은 다음과 같습니다.

var len = arr.length;
while (len--) {
    // blah blah
}

전체 비교는 http://blogs.oracle.com/greimer/entry/best_way_to_code_a 를 참조하십시오


답변

2016 년 6 월 현재 최신 Chrome에서 일부 테스트 (2016 년 5 월 브라우저 시장의 71 % 이상 증가) :

  • 가장 빠른 루프는 캐싱 길이의 유무에 관계없이 거의 비슷한 성능을 제공 하는 for 루프 입니다. 캐시 된 길이를 가진 for 루프는 캐싱없는 것보다 더 나은 결과를 제공하기도하지만 그 차이는 거의 무시할 수 있습니다. 즉, 엔진이 이미 표준을 선호하도록 최적화되어 있으며 아마도 캐싱없는 루프에 대해 가장 간단한 방법 일 것입니다.
  • 감소 된 while 루프는 for 루프보다 약 1.5 배 느 렸습니다.
  • 콜백 함수 (표준 forEach와 같은)를 사용하는 루프는 for 루프보다 약 10 배 느 렸습니다.

나는이 스레드가 너무 오래되었다고 생각하고 프로그래머가 길이를 캐싱하거나 더 나은 성능을 달성하기 위해 감소와 함께 리버스 트래버스를 사용해야한다고 생각하는 오해의 소지가 있습니다. 간단하고 간단한 for 루프보다 읽기 쉽고 오류가 발생하기 쉬운 코드를 작성하십시오. 따라서 다음을 권장합니다.

  • 앱이 많은 항목을 반복하거나 루프 코드가 자주 사용되는 함수 내에 있으면 간단한 for 루프가 답입니다.

    for (var i = 0; i < arr.length; i++) {
      // Do stuff with arr[i] or i
    }
  • 앱이 많은 항목을 실제로 반복하지 않거나 여기저기서 작은 반복을 수행 해야하는 경우 표준 forEach 콜백 또는 선택한 JS 라이브러리의 유사한 함수를 사용하면 이해하기 쉽고 오류가 덜 발생할 수 있습니다. 인덱스 변수 범위가 닫히고 대괄호를 사용하지 않고 배열 값에 직접 액세스 할 수 있습니다.

    arr.forEach(function(value, index) {
      // Do stuff with value or index
    });
  • 수십억 행을 반복하는 동안 몇 밀리 초를 긁어 내야하며 배열의 길이가 프로세스를 통해 변경되지 않으면 for 루프에서 길이를 캐싱하는 것을 고려할 수 있습니다. 요즘에는 이것이 실제로 필요하지 않다고 생각합니다.

    for (var i = 0, len = arr.length; i < len; i++) {
      // Do stuff with arr[i]
    }

답변

순서가 중요하지 않은 경우이 스타일을 선호합니다.

for(var i = array.length; i--; )

길이를 캐시하고 쓰기가 훨씬 짧습니다. 그러나 배열을 역순으로 반복합니다.


답변

2018 년에 업데이트가 좋을 수 있습니다 …

그리고 나는 정말로 받아 들여진 대답동의하지 않아야한다 . 다른 브라우저에서 지연됩니다. 일부 할 forEach몇 가지가 빠르고 for-loop, 일부 while
여기에 모든 방법에 대한 벤치 마크입니다 http://jsben.ch/mW36e

arr.forEach( a => {
  // ...
}

당신이 많이 위해 루프 등을 볼 수 있기 때문에 그리고 for(a = 0; ... )없이 ‘var에’변수는 전 세계적으로 정의 될 것이라고 언급하는 다음의 가치 및이 수는 느린거야, 그래서 극적으로 속도에 영향을 미칩니다.

더프의 장치는 오페라에서 더 빠르게 실행되지만 파이어 폭스에서는 그렇지 않습니다

var arr = arr = new Array(11111111).fill(255);
var benches =
[ [ "empty", () => {
  for(var a = 0, l = arr.length; a < l; a++);
}]
, ["for-loop", () => {
  for(var a = 0, l = arr.length; a < l; ++a)
    var b = arr[a] + 1;
}]
, ["for-loop++", () => {
  for(var a = 0, l = arr.length; a < l; a++)
    var b = arr[a] + 1;
}]
, ["for-loop - arr.length", () => {
  for(var a = 0; a < arr.length; ++a )
    var b = arr[a] + 1;
}]
, ["reverse for-loop", () => {
  for(var a = arr.length - 1; a >= 0; --a )
    var b = arr[a] + 1;
}]
,["while-loop", () => {
  var a = 0, l = arr.length;
  while( a < l ) {
    var b = arr[a] + 1;
    ++a;
  }
}]
, ["reverse-do-while-loop", () => {
  var a = arr.length - 1; // CAREFUL
  do {
    var b = arr[a] + 1;
  } while(a--);
}]
, ["forEach", () => {
  arr.forEach( a => {
    var b = a + 1;
  });
}]
, ["for const..in (only 3.3%)", () => {
  var ar = arr.slice(0,arr.length/33);
  for( const a in ar ) {
    var b = a + 1;
  }
}]
, ["for let..in (only 3.3%)", () => {
  var ar = arr.slice(0,arr.length/33);
  for( let a in ar ) {
    var b = a + 1;
  }
}]
, ["for var..in (only 3.3%)", () => {
  var ar = arr.slice(0,arr.length/33);
  for( var a in ar ) {
    var b = a + 1;
  }
}]
, ["Duff's device", () => {
  var len = arr.length;
  var i, n = len % 8 - 1;

  if (n > 0) {
    do {
      var b = arr[len-n] + 1;
    } while (--n); // n must be greater than 0 here
  }
  n = (len * 0.125) ^ 0;
  if (n > 0) {
    do {
      i = --n <<3;
      var b = arr[i] + 1;
      var c = arr[i+1] + 1;
      var d = arr[i+2] + 1;
      var e = arr[i+3] + 1;
      var f = arr[i+4] + 1;
      var g = arr[i+5] + 1;
      var h = arr[i+6] + 1;
      var k = arr[i+7] + 1;
    }
    while (n); // n must be greater than 0 here also
  }
}]];
function bench(title, f) {
  var t0 = performance.now();
  var res = f();
  return performance.now() - t0; // console.log(`${title} took ${t1-t0} msec`);
}
var globalVarTime = bench( "for-loop without 'var'", () => {
  // Here if you forget to put 'var' so variables'll be global
  for(a = 0, l = arr.length; a < l; ++a)
     var b = arr[a] + 1;
});
var times = benches.map( function(a) {
                      arr = new Array(11111111).fill(255);
                      return [a[0], bench(...a)]
                     }).sort( (a,b) => a[1]-b[1] );
var max = times[times.length-1][1];
times = times.map( a => {a[2] = (a[1]/max)*100; return a; } );
var template = (title, time, n) =>
  `<div>` +
    `<span>${title} &nbsp;</span>` +
    `<span style="width:${3+n/2}%">&nbsp;${Number(time.toFixed(3))}msec</span>` +
  `</div>`;

var strRes = times.map( t => template(...t) ).join("\n") +
            `<br><br>for-loop without 'var' ${globalVarTime} msec.`;
var $container = document.getElementById("container");
$container.innerHTML = strRes;
body { color:#fff; background:#333; font-family:helvetica; }
body > div > div {  clear:both   }
body > div > div > span {
  float:left;
  width:43%;
  margin:3px 0;
  text-align:right;
}
body > div > div > span:nth-child(2) {
  text-align:left;
  background:darkorange;
  animation:showup .37s .111s;
  -webkit-animation:showup .37s .111s;
}
@keyframes showup { from { width:0; } }
@-webkit-keyframes showup { from { width:0; } }
<div id="container"> </div>


답변

2014 년 While이 돌아왔다

논리적으로 생각하십시오.

이거 봐요

for( var index = 0 , length = array.length ; index < length ; index++ ) {

 //do stuff

}
  1. 최소 2 개의 변수 (인덱스, 길이)를 만들어야합니다
  2. 색인이 길이보다 작은 지 확인해야합니다.
  3. 인덱스를 늘려야 함
  4. for루프는 3 개 개의 매개 변수를 가지고

이제 왜 이것이 더 빠를까요?

var length = array.length;

while( --length ) { //or length--

 //do stuff

}
  1. 하나의 변수
  2. 수표 없음
  3. 지수가 감소합니다 (기계는 선호합니다)
  4. while 하나의 매개 변수 만 있음

Chrome 28에서 for 루프가 while보다 빠르다는 것을 알았을 때 나는 완전히 혼란 스러웠습니다. 이것은 일종의 벤이 있어야합니다

“어, 모두가 for 루프를 사용하고 있습니다. 크롬을 개발할 때 이것에 초점을 맞추겠습니다.”

그러나 이제 2014 년에 while 루프가 크롬으로 돌아 왔습니다. 2 배 더 빠르며, 다른 / 구형 브라우저에서는 항상 빠릅니다.

최근에 몇 가지 새로운 테스트를했습니다. 실제 환경에서 짧은 코드는 가치가 없으며 jsperf는 실제로 while 루프를 제대로 실행할 수 없습니다. 시간이 걸리는 array.length를 다시 만들어야하기 때문입니다.

jsperf에서 while 루프의 실제 속도를 얻을 수 없습니다.

당신은 당신의 자신의 사용자 정의 함수를 생성하고 확인해야 window.performance.now()

그리고 그래 … while 루프가 더 빠를 방법은 없습니다.

실제 문제는 실제로 dom 조작 / 렌더링 시간 / 드로잉 시간 또는 호출하고 싶습니다.

예를 들어 좌표와 충돌을 계산 해야하는 캔버스 장면이 있습니다 … 10-200 MicroSeconds (밀리 초가 아닌) 사이에 수행됩니다. 실제로 모든 것을 렌더링하는 데 몇 밀리 초가 걸립니다. DOM에서와 동일합니다.

그러나

loop경우에 따라 for 를 사용하는 또 다른 수퍼 퍼포먼스 방법이 있습니다 … 예 : 배열 복사 / 복제

for(
 var i = array.length ;
 i > 0 ;
 arrayCopy[ --i ] = array[ i ] // doing stuff
);

매개 변수 설정을 확인하십시오.

  1. while 루프와 동일하지만 하나의 변수 만 사용하고 있습니다.
  2. 인덱스가 0보다 큰지 확인해야합니다.
  3. 보시다시피,이 접근법은 모든 사람들이 사용하는 표준 for 루프와 다릅니다 .3 번째 매개 변수 내부에서 작업을 수행하고 배열 내부에서 직접 감소합니다.

말했다, 이것은 확인 같은 기계-

나는 그것을 조금 더 짧게 만들고 쓸모없는 것들을 제거하고 같은 스타일을 사용하여 이것을 썼다고 생각했습니다.

for(
 var i = array.length ;
 i-- ;
 arrayCopy[ i ] = array[ i ] // doing stuff
);

짧아도 i한 번 더 사용 하면 모든 속도가 느려집니다. 이전 for루프와 루프 보다 1/5 느립니다 while.

참고 :;없이 looo의 후 매우 중요하다{}

방금 jsperf가 스크립트를 테스트하는 가장 좋은 방법은 아니라고 말했더라도 .. 여기에 2 개의 루프가 추가되었습니다.

http://jsperf.com/caching-array-length/40

그리고 여기 자바 스크립트의 성능에 대한 또 다른 대답이 있습니다.

https://stackoverflow.com/a/21353032/2450730

이 답변은 자바 스크립트 작성 방법을 보여줍니다. 당신이 그것을 읽을 수 없다면, 당신은 자바 스크립트에 대한 답변을 얻거나 책을 읽습니다 http://www.ecma-international.org/ecma-262/5.1/


답변

http://jsperf.com/caching-array-length/60

내가 준비한 (오래된 것을 재사용함으로써) 테스트의 최신 개정판이 한 가지를 보여줍니다.

캐싱 길이는 그다지 중요하지 않지만 해를 끼치 지 않습니다.

위에서 새로 링크 된 탭에서 테스트를 처음 실행할 때마다 데비안 스퀴즈 64 비트 ( 데스크탑 하드웨어 )의 Chrome, Opera 및 Firefox에서 마지막 4 개의 스 니펫 (차트에서 3, 5, 7 및 10 번째 차트)에 대한 최상의 결과를 얻습니다. ). 후속 실행은 상당히 다른 결과를 제공합니다.

성능 측면의 결론은 간단합니다.

  • for 루프 (앞으로)로 이동하고 !==대신을 사용하여 테스트하십시오 <.
  • 나중에 배열을 다시 사용할 필요가 없으면 shift()줄어든 길이의 루프와 파괴적인 배열의 while 루프 도 효율적입니다.

tl; dr

현재 아래 패턴 (2011.10)이 가장 빠른 것으로 보입니다.

for (var i = 0, len = arr.length; i !== len; i++) {
    ...
}

arr.length여기서 캐싱 은 중요하지 않으므로 테스트 만하면 i !== arr.length성능이 떨어지지 않지만 코드가 짧아집니다.


추신 : 나는 shift()그 결과가있는 스 니펫에서 0 번째 요소에 액세스하는 대신 사용할 수 있다는 것을 알고 있지만 이전 개정을 재사용 한 후 (루프가 잘못 되었음) 나중에 간과하고 이미 얻은 결과를 잃고 싶지는 않았습니다.