[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
}
실제로 어떤 방법이 가장 좋은지 알고 싶습니다.
답변
대부분의 최신 브라우저에서이 테스트를 수행 한 후 …
현재 가장 빠른 형태의 루프 (그리고 내 의견으로는 가장 문법적으로 명백합니다).
길이 캐싱이있는 루프의 표준
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} </span>` +
`<span style="width:${3+n/2}%"> ${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
}
- 최소 2 개의 변수 (인덱스, 길이)를 만들어야합니다
- 색인이 길이보다 작은 지 확인해야합니다.
- 인덱스를 늘려야 함
for
루프는 3 개 개의 매개 변수를 가지고
이제 왜 이것이 더 빠를까요?
var length = array.length;
while( --length ) { //or length--
//do stuff
}
- 하나의 변수
- 수표 없음
- 지수가 감소합니다 (기계는 선호합니다)
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
);
매개 변수 설정을 확인하십시오.
- while 루프와 동일하지만 하나의 변수 만 사용하고 있습니다.
- 인덱스가 0보다 큰지 확인해야합니다.
- 보시다시피,이 접근법은 모든 사람들이 사용하는 표준 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 번째 요소에 액세스하는 대신 사용할 수 있다는 것을 알고 있지만 이전 개정을 재사용 한 후 (루프가 잘못 되었음) 나중에 간과하고 이미 얻은 결과를 잃고 싶지는 않았습니다.