[React다루는기술] 23. redux-saga에 앞서 제너레이터 함수(generator function)


React 에서 redux-saga 의 비동기 작업을 하기 전에 제너레이터 함수에 대한 포스팅이다. 제너레이터 함수(generator function)는 일반 함수와는 다르게 실행 중간에 멈출 수 있고, 필요할 때 다시 시작할 수 있는 함수입니다. 제너레이터 함수는 함수 내부에 yield 키워드를 사용하여 값을 반환하고 함수 실행을 일시 중지시킬 수 있다.


1. 제너레이터 함수 function*

일반 함수는 하나의 값(혹은 0개의 값)만을 반환하지만 제너레이터(generator)를 사용하면 여러 개의 값을 필요에 따라 하나씩 반환(yield)할 수 있습니다. 제너레이터와 이터러블 객체를 함께 사용하면 손쉽게 데이터 스트림을 만들 수 있다. 여기서 yield는 ‘생산하다, 산출하다’라는 의미이다.

제너레이터를 만들려면 ‘제너레이터 함수’라 불리는 특별한 문법 구조, function* 으로 함수를 선언한다.

제너레이터 함수는 일반 함수와 동작 방식이 다릅니다. 제너레이터 함수를 호출하면 코드가 실행되지 않고, 대신 실행을 처리하는 특별 객체, 제너레이터 객체가 반환됩니다.

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

// '제너레이터 함수'는 '제너레이터 객체'를 생성합니다.
let generator = generatorFunction();
alert(generator); // [object Generator]

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


next()는 제너레이터의 주요 메서드로 next()를 호출하면 가장 가까운 yield <value>문을 만날 때까지 실행이 지속된다. yield 문을 만나면 value를 반환한다.(더 이상 없는 경우 undefined) next()는 항상 아래 두 프로퍼티를 가진 객체를 반환

  • value: 산출 값
  • done: 함수 코드 실행이 끝났으면 true, 아니라면 false


제너레이터 다른 예제

function* generatorFunction(x, y) {
  yield x + y;
  yield x - y;
}

const generator = generatorFunction(5, 3);
console.log(generator.next()); // { value: 8, done: false }
console.log(generator.next()); // { value: 2, done: false }
console.log(generator.next()); // { value: undefined, done: true }


function* generatorFunction(x, y) {
  yield x + y;
  yield x - y;
  yield x * y;
  return 9;
}

//제너레이터와 이터러블
const generator = generatorFunction(11, 4);
for(let value of generator) {
  console.log(value); // 15, 7, 44
}


function* generatorFunction(a) {
 console.log('# a = ', a)
 let b = yield;
 console.log('# b = ', b)
 yield a + b;
 let c = yield;
 console.log('# c = ', c)
 yield a + b + c;
}

const generator = generatorFunction(10);
console.log(generator.next())
console.log(generator.next(2))
console.log(generator.next())
console.log(generator.next(4))
# a = 10
(2) {value: undefined, done: false}
# b = 2
(2) {value: 12, done: false}
(2) {value: undefined, done: false}
# c = 4
(2) {value: 16, done: false}


function* fibonacciGenerator(a, b) {
  while (true) {
    //console.log(a, b)
    yield a;
    [a, b] = [b, a + b];
  }
}

// 피보나치 수열의 첫 10개 숫자 출력
const fibonacciSequence = fibonacciGenerator(0, 1);
for (let i = 0; i < 10; i++) {
  console.log(fibonacciSequence.next().value);
}