본문 바로가기
Dev/javascript

Generator Function - 제너레이터 함수

by 괴발짜응 2025. 2. 21.
반응형

제너레이터 함수는 자바스크립에서 순회 가능한(iterable) 객체를 생성하거나, 함수의 실행을 중간에 일시 중단(pause)하고 다시 재개(resume)할 수 있도록 해주는 특별한 함수다. 제너레이터 함수는 일반 함수와 다르게 실행 흐름을 제어할 수 있는 강력한 기능을 제공한다. 


1. 제너레이터 함수의 정의와 문법

제너레이터 함수는 함수 선언문 앞에 *를 붙여 정의하며, 함수 내에서 yield  키워드를 사용하여 값을 반환한다.

function* myGenerator() {
  yield 1;
  yield 2;
  yield 3;
}

 

2. yield 키워드와 실행 흐름 제어

yield의 역할:

yield는 함수의 실행을 일시 중단하고, 호출자에게 특정 값을 반환하는 역할을 한다. 제너레이터 함수는 yield에서 멈춘 후, 다시 호출자의 요청(next() 메서드 호출)이 있을 때 중단된 위치부터 실행을 재개한다.

function* myGenerator() {
  console.log("제너레이터 시작");
  yield 10; // 첫 번째 yield: 실행 중단 후 10 반환
  console.log("재개됨");
  yield 20; // 두 번째 yield: 실행 중단 후 20 반환
  console.log("종료 직전");
  return 30; // 함수 종료, return 값은 done: true로 반환
}

const gen = myGenerator();

console.log(gen.next()); // { value: 10, done: false }
console.log(gen.next()); // { value: 20, done: false }
console.log(gen.next()); // { value: 30, done: true }
console.log(gen.next()); // { value: undefined, done: true }

위 코드를 보면, next() 호출마다 제너레이터 내부의 실행이 재개되며 yield에서 지정한 값이 순차적으로 반환되는 것을 볼 수 있다.

 

3. 이터레이터 프로토콜과 for...of 루프

이터레이터 객체:

제너레이터 함수는 Iterator 프로토콜을 따르는 객체를 반환한다. 이 객체는 next() 메서드를 가지고 있으며, 각 호출마다 { value, done }형태의 객체를 반환한다.

 

for...of 루프와의 통합:

제너레이터 함수가 반환하는 객체는 순회(iteration)가 가능하므로, for...of 루프를 사용해 간편하게 값을 순회할 수 있다.

function* counter() {
  let i = 0;
  while (i < 3) {
    yield i++;
  }
}

for (const num of counter()) {
  console.log(num); // 0, 1, 2가 순서대로 출력됨
}

 

4. yield*를 통한 위임(Delegation)

yield*의 역할:

제너레이터 내부에서 다른 이터블 객체나 제너레이터를 호출하여 그 값을 순차적으로 "위임"할 수 있다.

function* innerGenerator() {
  yield "a";
  yield "b";
}

function* outerGenerator() {
  yield 1;
  yield* innerGenerator(); // innerGenerator의 모든 yield 값을 위임
  yield 2;
}

for (const value of outerGenerator()) {
  console.log(value); // 1, "a", "b", 2 출력
}

 

5. 제너레이터 함수의 활용 및 응용

비동기 제어 흐름:

제너레이터를 사용하면, 복잡한비동기 코드를 동기적인 흐름처럼 작성할 수 있다. 현재는 async/await 가 주로 사용되지만, 초기에는 제너레이터를 활용한 비동기 제어 기법이 많이 사용되었다.

 

상태 유지:

함수 실행 중간에 상태를 저장하고, 필요할 때마다 재개할 수 있기 때문에, 반복적인 작업이나 무한 이터레이터를 구현할 때 유용하다.

 

코드의 모듈화:

복잡한 순회 로직을 제너레이터로 분리하여, 코드의 가독성과 재사용성을 높일 수 있다.

 

6. 에러 처리와 제너레이터

throw 메서드:

반환된 이터레이터 객체에는 throw() 메서드가 있어, 제너레이터 내부에 예외를 전달할 수 있다.

function* errorGenerator() {
  try {
    yield 1;
    yield 2;
  } catch (err) {
    console.log("에러 처리:", err);
  }
}

const gen = errorGenerator();
console.log(gen.next()); // { value: 1, done: false }
gen.throw(new Error("문제 발생")); // "에러 처리: Error: 문제 발생" 출력
console.log(gen.next()); // { value: undefined, done: true }

 

반응형