JavaScript 배열 메서드 성능 비교 - forEach vs for vs for...of
문제 상황
사용자 데이터 15만 건을 가공하는 배치 스크립트의 실행 시간이 3분을 넘어갔다. 프로파일링 결과 배열 순회 로직이 병목이었다.
기존 코드는 forEach를 사용하고 있었다.
users.forEach(user => {
processedData.push({
id: user.id,
name: normalizeString(user.name),
score: calculateScore(user.activities)
});
});
성능 측정
15만 건 기준으로 각 방식을 측정했다.
// 1. forEach
console.time('forEach');
users.forEach(user => transform(user));
console.timeEnd('forEach');
// 결과: 287ms
// 2. for loop
console.time('for');
for (let i = 0; i < users.length; i++) {
transform(users[i]);
}
console.timeEnd('for');
// 결과: 98ms
// 3. for...of
console.time('for-of');
for (const user of users) {
transform(user);
}
console.timeEnd('for-of');
// 결과: 102ms
결론
전통적인 for 루프가 가장 빨랐다. forEach는 함수 호출 오버헤드가 있어 대량 데이터에서 약 3배 느렸다.
for...of는 가독성과 성능의 균형이 좋았다. Iterator 프로토콜을 사용하지만 실제 성능은 for와 비슷했다.
최종적으로 배치 스크립트는 for 루프로 변경했고, 실행 시간이 1분 10초로 단축됐다. 일반적인 비즈니스 로직에서는 forEach나 for...of의 가독성이 더 중요하지만, 성능이 critical한 경우는 여전히 전통적인 방식이 유효했다.
참고사항
- Node.js 8.11 환경
- V8 엔진 최적화는 계속 개선되므로 주기적 재측정 필요
map,filter등은 체이닝 가능하지만 중간 배열 생성으로 메모리 사용량 증가