본문 바로가기
자바스크립트(JavaScript)/자바스크립트

[JavaScript] Generator Function / 제너레이터 함수

by yerica 2024. 12. 11.

Generator 함수

ES6에서부터 도입된 Generator 함수는 일반 함수와는 다르게 실행을 중간에 멈추거나 다시 시작할 수 있는 특수한 함수다. 이 함수는 끝에 별표가 있는 function* 키워드로 정의되며, yield 키워드를 사용하여 실행을 중단하거나 값을 반환할 수 있다. Generator 함수는 이터레이터(Iterator)를 생성하며, 호출 시 바로 실행되지 않고 이터레이터에 객체를 반환한다. 이후 next(), return(), throw()와 같은 인스턴스 메서드를 호출하여 단계적으로 실행을 제어한다.

 

  • .next() : yield 표현식을 통해 yield 된 값을 반환한다.
  • .return() : 주어진 값을 반환하고 제너레이터를 종료한다. 
  • .next() : 제너레이터에 오류를 발생시킨다.

Generator 함수는 일반 함수보다 좀 더 특정한 상황에서 사용되는데, 모든 프로젝트에서 자주 사용되지는 않지만 다음과 같은 상황에서 유용하게 사용된다

 

1. 이터레이터 구현

Generator는 이터레이터 객체를 쉽게 생성할 수 있도록 설계되어있다.
function* genFnc() {
    yield 1; // 첫 번째 값
    yield 2; // 두 번째 값
    yield 3; // 세 번째 값
}

const iterator = genFnc();

console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { value: undefined, done: true }​

 

2. 데이터 스트리밍 및 대용량 데이터 처리

필요할 때만 데이터를 생성하거나 가져오는 작업에 유용하다.
function* infinite() {
  let index = 0;
  while (true) {
    yield index++;
  }
}

const generator = infinite(); // "Generator { }"

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

 

3. 비동기 작업 제어

async / await 가 널리 사용되기 전에는 비동기 흐름을 제어하기 위해 Generator가 사용되었다.
현재는 async / await 또는 간단한 패턴을 사용하는 것이 더 일반적이다.
redux-saga 같은 상태 관리 라이브러리에서 비동기 액션 흐름을 제어하는데 Generator를 사용하고 있다.


4. 제어된 계산 흐름

코드의 실행을 중단하고 특정 시점에서 다시 시작해야할 때 유용하다.
function* stepByStep() {
    const num1 = yield "Enter first number"; // 첫 번째 중단
    const num2 = yield "Enter second number"; // 두 번째 중단
    return num1 + num2; // 최종 반환
}

const generator = stepByStep();
console.log(generator.next().value); // "Enter first number"
console.log(generator.next(10).value); // "Enter second number"
console.log(generator.next(20).value); // 30

 

5. 조합 가능한 데이터 흐름

데이터 처리가 연속적인 단계를 거쳐야 할 때 유용하다.
function* dataPipeline(data) {
    for (let item of data) {
        yield item * 2; // 데이터를 처리하고 반환
    }
}

const pipeline = dataPipeline([1, 2, 3, 4]);
for (const result of pipeline) {
    console.log(result); // 2, 4, 6, 8
}

 

Generator 함수의 장단점
장점 메모리 효율적 데이터를 한꺼번에 메모리에 올리지 않고, 필요할 때만 생성하여 메모리를 절약할 수 있다.
코드의 흐름 제어 실행을 중단하고 다시 시작할 수 있어, 특정한 제어 흐름이 필요한 작업에 적합하다.
이터레이터와의 쉬운 통합 for...of, spread, Array.from 등 이터러블과 자연스럽게 통합된다.
단점 난해한 디버깅 yield와 next()가 연속적으로 사용되므로, 실행 흐름을 추적하기 어려울 수 있다.
일반 함수보다 덜 직관적 익숙하지 않은 사람들에게는 복잡하게 느껴질 수 있다.
자주 쓰이지 않음 많은 경우, async/await이나 다른 간단한 패턴으로 대체 가능하기 때문에 프로젝트에서 자주 보이지 않을 수 있다.
자주
사용
되는
Redux-Saga Redux 상태 관리 라이브러리에서 비동기 액션 흐름을 제어하는 데 Generator를 사용한다.
대규모 데이터 처리 예: 로그 데이터 처리, 무한 스크롤 구현.
커스텀 이터레이터 구현 고유한 순회를 정의해야 할 때 사용된다.