본문 바로가기

언어(JS,TS)/JavaScript

JS [test: forEach VS map VS for (속도 차이 및 원인 분석)]

반응형

맨날 코드 쓰다보니 뭐가 더 효율적인지 잘 몰라서 case별로 나누에서 테스트를 통하여 직접 알아보기로 하였다.

 

환경: node-v : v20.11.1
실행 코드 : node test.js

 

case는 총 4가지로 준비하였다.

1. 단순반복

2. 계산반복

3. 배열 데이터 변형 후 삽입

4. 새로운 배열 생성

    4-1. 새로운 방식(push 영향 확인)

 

 

실험 하다보니 알게된 사실인데 같은 코드를 실행하여도 걸리는 시간이 달라진다.

계산량을 늘리던가 여러번 돌려서 평균값으로 적던가 하는 방법으로 추가로 실험이 필요해 보인다.

 

case 1 (단순 반복)

테스트 코드

const testArray = Array.from({ length: 1_000_000 }, (_, i) => i);

// 'for' 루프 시간 측정
console.time('for');
for (let i = 0; i < testArray.length; i++) {
	// empty
}
console.timeEnd('for');

// 'forEach' 시간 측정
console.time('forEach');
testArray.forEach((value) => {
	// empty
});
console.timeEnd('forEach');

// 'map' 시간 측정
console.time('map');
testArray.map((x) => {
	// empty
});
console.timeEnd('map');
/*
결과 
for: 1.45ms
forEach: 5.99ms
map: 10.101ms
*/

결과

for: 1.45ms
forEach: 5.99ms
map: 10.101ms

 

- for가 기본 속도는 가장 빨랐다.

 

 

case 2 (계산 반복)

테스트 코드

const testArray = Array.from({ length: 1_000_000 }, (_, i) => i);

// 'for' 루프 시간 측정
console.time('for');
let forSum = 0;
for (let i = 0; i < testArray.length; i++) {
	forSum += 1;
}
console.timeEnd('for');

// 'forEach' 시간 측정
console.time('forEach');
let forEachSum = 0;
testArray.forEach((value, idx) => {
	forEachSum += 1;
});
console.timeEnd('forEach');

// 'map' 시간 측정
console.time('map');
let mapSum = 0;
testArray.map((x) => {
	mapSum += 1;
});
console.timeEnd('map');
/**
결과
for: 1.811ms
forEach: 6.149ms
map: 10.263ms   
*/

 

결과

for: 1.811ms
forEach: 6.149ms
map: 10.263ms   

 

마찬가지로 for이 가장 빠름

 

case 3 배열 데이터 변형 후 삽입

// 'for' 루프 시간 측정
let testArray1 = Array.from({ length: 1_000_000 }, (_, i) => i);
console.time('for');
for (let i = 0; i < testArray1.length; i++) {
	testArray1[i] += 1;
}
console.timeEnd('for');

// 'forEach' 시간 측정
let testArray2 = Array.from({ length: 1_000_000 }, (_, i) => i);
console.time('forEach');
testArray2.forEach((value, idx) => {
	testArray2[idx] += 1;
});
console.timeEnd('forEach');

// 'map' 시간 측정
let testArray3 = Array.from({ length: 1_000_000 }, (_, i) => i);
console.time('map');
testArray3 = testArray3.map((x) => {
	x += 1;
	return x;
});
console.timeEnd('map');

/**
결과
for: 2.202ms
forEach: 6.759ms
map: 9.521ms
*/

 

결과

for: 2.202ms
forEach: 6.759ms
map: 9.521ms

 

- for이 가장 빠르다 

- 특이점은 map의 경우 항상 return 값이 있어서 그런가 배열 변형은 그냥 return 없이 돌리는 것보다 빨랐다.

 

 

case 4 새로운 배열 생성

// 'for' 루프 시간 측정
const testArray1 = Array.from({ length: 1_000_000 }, (_, i) => i);
console.time('for');
let testArray1_1 = [];
for (let i = 0; i < testArray1.length; i++) {
	testArray1_1.push(testArray1[i] + i);
}
console.timeEnd('for');

// 'forEach' 시간 측정
const testArray2 = Array.from({ length: 1_000_000 }, (_, i) => i);
console.time('forEach');
let testArray2_1 = [];
testArray2.forEach((value, idx) => {
	testArray2_1.push(testArray2[idx] + idx);
});
console.timeEnd('forEach');

// 'map' 시간 측정
const testArray3 = Array.from({ length: 1_000_000 }, (_, i) => i);
console.time('map');
let testArray3_1 = testArray3.map((x, idx) => {
	x += idx;
	return x;
});
console.timeEnd('map');

/**
결과
for: 15.041ms
forEach: 18.626ms
map: 9.386ms
*/

결과

for: 15.041ms
forEach: 18.626ms
map: 9.386ms

 

- map이 가장 빨랐다 

- push 함수의 영향일 가능성이 높아보였다 (새로운 케이스 추가)

 

 

 

case 4-1 새로운 배열 생성(push제외)

push 함수를 반복적으로 사용하므로 push 영향 확인

map의 특징은 같은 길이의 새로운 함수를 만든 다는 것이므로 같은 길이의 배열을 새로 만들고 삽입만 하는 식으로 진행

// 'for' 루프 시간 측정
const testArray1 = Array.from({ length: 1_000_000 }, (_, i) => i);
console.time('for');
let testArray1_1 = new Array(1_000_000);
for (let i = 0; i < testArray1.length; i++) {
	let value = testArray1[i];
	testArray1_1[i] = value + i;
}
console.timeEnd('for');

// 'forEach' 시간 측정
const testArray2 = Array.from({ length: 1_000_000 }, (_, i) => i);
console.time('forEach');
let testArray2_1 = new Array(1_000_000);
testArray2.forEach((value, idx) => {
	testArray2_1[idx] = value + idx;
});
console.timeEnd('forEach');

// 'map' 시간 측정
const testArray3 = Array.from({ length: 1_000_000 }, (_, i) => i);
console.time('map');
let testArray3_1 = testArray3.map((x, idx) => {
	x += idx;
	return x;
});
console.timeEnd('map');

/**
결과
for: 5.608ms
forEach: 9.601ms
map: 9.524ms
*/

결과

for: 5.608ms
forEach: 9.601ms
map: 9.524ms

 

- push의 영향이 확실히 있다

- 이런식으로 하면 for이 확실히 더 빨랐다.

- 이쯤오면 map과 forEach의 속도는 비슷해 졌다.

- for이 더 빠른이유는 함수의 사용 여부로 예상된다. (케이스 추가 예정)

 

 

TODO

(+ 그럼 for문 과 map에서 시간이 차이나는 원인 파악하기)

(+ for문이 무조건 빠르면 custum으로 map을 만들면 더빠른가? )
(+ https://leanylabs.com/blog/js-forEach-map-reduce-vs-for-for_of/ 이 링크의 정보를 토대로 데이터 정리해보기)