본문 바로가기
JavaScript

[JavaScript] 지연 평가(Lazy Evaluation)

by teamnova 2025. 1. 16.
728x90

프로그래밍에서 지연 평가(Lazy Evaluation)는 계산을 미루는 기법으로, 데이터가 실제로 필요할 때 계산을 수행하는 방식을 의미합니다. 함수형 프로그래밍에서 자주 사용되는 이 개념은 메모리 사용을 최적화하고, 불필요한 계산을 줄이는 데 매우 유용합니다.
이번 글에서는 자바스크립트에서 지연 평가를 구현하는 방법에 대해 알아보겠습니다.

1. 지연 평가란?

지연 평가는 값이 필요할 때까지 계산을 미루는 전략입니다.

즉, 어떤 표현식이나 함수 호출의 결과를 바로 계산하지 않고, 실제로 사용될 때 계산을 수행합니다.

동작 방식

  • 즉시 평가(Eager Evaluation): 표현식을 만나면 바로 계산합니다.
  • 지연 평가(Lazy Evaluation): 표현식을 만나도 계산을 미루고, 필요할 때 계산합니다.
// 즉시 평가
const eagerValue = 2 + 3; // 바로 계산되어 5가 할당됩니다.

// 지연 평가
const lazyValue = () => 2 + 3; // 계산을 함수로 감싸서 필요할 때 실행됩니다.

console.log(lazyValue()); // 실제로 호출할 때 계산됩니다.

 

장점

  • 성능 최적화: 필요한 데이터만 계산하므로 불필요한 작업을 줄임. 대규모 데이터 처리나 무한 시퀀스와 같은 경우에 효과적.
  • 무한 데이터 처리: 무한 시퀀스와 같은 데이터 구조를 처리 가능.
  • 메모리 효율성: 데이터 전체를 메모리에 로드하지 않고 필요한 만큼만 계산.

단점

  • 디버깅의 어려움: 계산이 미뤄지기 때문에 디버깅이 복잡해질 수 있음.
  • 복잡한 구현: 즉시 평가보다 구현이 복잡할 수 있음.
  • 의도하지 않은 계산 지연: 지연 평가를 잘못 사용하면 오히려 성능 문제가 발생할 수 있음.

 

2. 자바스크립트에서의 지연 평가

자바스크립트는 기본적으로 즉시 평가를 사용하지만, 지연 평가를 구현할 수 있는 몇 가지 방법을 제공합니다.

2.1 함수로 지연 평가 구현

가장 간단한 방법은 계산을 함수로 감싸는 것입니다.

const lazyValue = () => {
  console.log('계산 중...');
  return 2 + 3;
};

console.log('계산 전');
console.log(lazyValue()); // 실제로 호출할 때 계산
console.log('계산 완료');

 

출력

더보기

계산 전
계산 중...
5
계산 완료

2.2 제너레이터를 활용한 지연 평가

자바스크립트의 제너레이터(Generator)는 지연 평가를 구현하는 강력한 도구입니다.

제너레이터는 값을 필요할 때마다 생성하므로, 계산을 미룰 수 있습니다.

예제: 제너레이터로 무한 시퀀스 생성

function* infiniteSequence() {
  let i = 0;
  while (true) {
    yield i++; // 값을 반환하고, 다음 호출까지 계산을 멈춤
  }
}

const sequence = infiniteSequence();

console.log(sequence.next().value); // 0
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 2

위 코드에서 infiniteSequence는 무한한 숫자 시퀀스를 생성하지만, 실제로 사용된 값만 계산합니다.

2.3 Iterable과 Lazy Mapping

지연 평가를 활용하여 배열과 같은 데이터 구조를 효율적으로 처리할 수도 있습니다.


예제: 제너레이터로 Lazy Mapping 구현

function* lazyMap(arr, fn) {
  for (const item of arr) {
    yield fn(item); // 각 아이템에 함수를 적용하고 결과를 반환
  }
}

const numbers = [1, 2, 3, 4, 5];
const lazyMapped = lazyMap(numbers, x => x * 2);

console.log([...lazyMapped]); // [2, 4, 6, 8, 10]

 

2.4 Lodash의 Lazy Evaluation

Lodash 라이브러리는 지연 평가를 기본적으로 지원합니다.

특히, _.chain을 사용하면 지연 평가를 통해 효율적인 데이터 처리가 가능합니다.

https://lodash.com/

 

Lodash

_.defaults({ 'a': 1 }, { 'a': 3, 'b': 2 });_.partition([1, 2, 3, 4], n => n % 2);DownloadLodash is released under the MIT license & supports modern environments. Review the build differences & pick one that’s right for you.InstallationIn

lodash.com

 

예제: Lodash로 Lazy Evaluation

const _ = require('lodash');

const result = _.chain([1, 2, 3, 4])
  .map(x => x * 2) // 모든 요소에 2를 곱함
  .filter(x => x > 4) // 4보다 큰 값만 필터링
  .value(); // 최종 계산 실행

console.log(result); // [6, 8]

 

3. 예제

무한 피보나치 수열 생성

지연 평가를 사용하면 무한 피보나치 수열을 쉽게 생성할 수 있습니다.

function* fibonacci() {
  let [prev, curr] = [0, 1];
  while (true) {
    yield curr;
    [prev, curr] = [curr, prev + curr];
  }
}

const fib = fibonacci();

console.log(fib.next().value); // 1
console.log(fib.next().value); // 1
console.log(fib.next().value); // 2
console.log(fib.next().value); // 3
console.log(fib.next().value); // 5

 

대규모 데이터 처리

지연 평가를 사용하여 대규모 데이터를 효율적으로 처리할 수 있습니다.

function* largeDataProcessor(data) {
  for (const item of data) {
    if (item % 2 === 0) {
      yield item * 2; // 짝수만 두 배로 변환
    }
  }
}

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

console.log([...processed].slice(0, 10)); // 첫 10개의 결과만 확인