비교할 문제

Array 메서드 성능 측정에서 확인할 질문은 같은 숫자 합계를 만드는 for, for...ofreduce의 비용은 현재 runtime에서 어떻게 다른가입니다. 세 후보가 같은 숫자 합계와 오류 동작을 만들어야 합니다. 새 배열을 만드는 map·filter는 결과 계약이 달라 이 측정 후보에서 제외합니다. 결과값, 순서, 오류 처리와 부수 효과가 다르면 같은 성능 비교가 아닙니다. 먼저 두 후보가 같은 일을 하는지 작은 입력으로 확인합니다.

원인 분석과 재현

map은 새 배열을 만들고 filter는 원소를 고르며 reduce는 값을 접으므로 같은 결과를 만들 때만 loop와 비용을 비교합니다.

작은 배열 100개, 중간 배열 10만 개, 객체 원소와 숫자 원소를 나누고 현재 지원하는 browser·Node version에서 각각 측정합니다. runtime version, 운영체제, CPU와 memory 제한도 결과와 함께 기록합니다.

비교 질문은 같은 숫자 합계를 만드는 for, for...ofreduce의 비용은 현재 runtime에서 어떻게 다른가입니다.

후보 유리한 조건 함께 치르는 비용
for index와 조기 종료를 세밀하게 제어 명령형 상태 변경이 늘 수 있음
for...of iterator 기반의 읽기 쉬운 순회 runtime·입력 형태에 따라 iterator 비용이 달라짐
reduce 하나의 누적값으로 접는 의도가 분명 callback과 복잡한 accumulator 비용
const values = Array.from({ length: 100_000 }, (_, i) => i);
const cases = {
  forLoop() { let sum = 0; for (let i = 0; i < values.length; i += 1) sum += values[i]; return sum; },
  forOf() { let sum = 0; for (const value of values) sum += value; return sum; },
  reduce() { return values.reduce((sum, value) => sum + value, 0); },
};
for (const fn of Object.values(cases)) for (let i = 0; i < 20; i += 1) fn(); // warm-up
for (const [name, fn] of Object.entries(cases)) {
  const samples = []; let checksum = 0;
  for (let run = 0; run < 30; run += 1) {
    const start = performance.now(); checksum ^= fn(); samples.push(performance.now() - start);
  }
  samples.sort((a, b) => a - b);
  console.log(name, { median: samples[15], p95: samples[28], checksum });
}

해결 방안과 판정

warm-up과 측정 구간을 나누고 여러 번 반복합니다. 서비스 지연은 median과 p95를, 처리량 비교는 단위 시간당 완료 수와 오류율을 함께 기록합니다. CPU time, allocation, RSS·heap, GC, I/O 중 이 작업에 직접 관련된 지표만 선택합니다. 단순 합계에서는 loop가 유리할 가능성이 있지만 JIT와 입력 형태에 따라 차이는 바뀝니다. 결과 배열이 필요한 작업에는 이 순위를 적용하지 않고 map·filter를 별도 계약으로 측정합니다.

차이가 반복 실행의 흔들림보다 작다면 더 단순하고 읽기 쉬운 구현을 선택합니다. 차이가 충분히 크더라도 실제 요청 전체의 지연과 자원 사용이 개선되는지 확인한 뒤 적용합니다.

공식 문서와 적용 범위

문서의 기본값과 동작은 version에 따라 달라질 수 있습니다. 현재 runtime·framework version, 실제 입력과 요청 흐름에서 다시 확인합니다.