[JS] 제너레이터란?

chaevivi·2023년 9월 4일
0
post-thumbnail

제너레이터 함수란?

ES6에 도입된 제너레이터(generator)는 코드 블록의 실행을 일시 중지했다가 필요한 시점에 재개할 수 있는 특수한 함수이다. (모던 JS 딥다이브 참고)

  • 제너레이터 함수는 실행이 연속적이지 않은 하나의 함수를 작성함으로서 개발자가 iterative algorithm을 정의할 수 있도록 해준다.


1. 일반 함수와의 차이점

(1) 제너레이터 함수는 함수 호출자에게 함수 실행의 제어권을 양도할 수 있다.

  • 일반 함수의 함수 호출자(caller)는 함수를 호출한 이후 함수 실행을 제어할 수 없다.
  • 제너레이터 함수는 함수의 제어권을 함수가 독점하지 않고 함수 호출자에게 양도(yield)하여, 함수 호출자가 함수 실행을 일시 중지시키거나 재개시킬 수 있다.
    • yield

(2) 제너레이터 함수는 함수 호출자와 함수의 상태를 주고받을 수 있다.

  • 일반 함수는 함수가 실행되고 있는 동안에는 함수 외부에서 내부로 값을 전달하여 함수의 상태를 변경할 수 없다.
  • 제너레이터 함수는 함수 호출자에게 상태를 전달할 수 있고 함수 호출자로부터 상태를 전달받을 수 있다.
    - next, yield

(3) 제너레이터 함수를 호출하면 제너레이터 객체를 반환한다.

  • 일반 함수를 호출하면 함수 코드를 일괄 실행하고 값을 반환한다.
  • 제너레이터 함수를 호출하면 함수 코드를 실행하는 것이 아니라 제너레이터 객체를 반환한다.


2. 제너레이터 함수 사용법

  • function* 키워드를 사용하고, 하나 이상의 yield 표현식을 포함한다.
  • yield 키워드는 제너레이터 함수의 실행을 일시 중지시키거나 yield 키워드 뒤에 오는 표현식의 평가 결과를 제너레이터 함수 호출자에게 반환한다.
    function* genFunc() {
      yield 1;
    }
  • 제너레이터 함수는 화살표 함수로 정의할 수 없다.
    const genFunc() = *() => {
      yield 1;
    };    // SyntaxError


3. 제너레이터 객체

  • 제너레이터 함수를 호출하면 생성되는 제너레이터 객체는 이터러블이면서 이터레이터이다.

  • 다시 말해, 제너레이터 객체는 반복할 수 있고, next() 메서드로 value, done 속성의 값을 반환할 수 있다.

  • next 메서드를 호출하면 제너레이터 함수의 yield 표현식까지 코드 블록을 실행하고, valuedone 프로퍼티 값으로 갖는 이터레이터 리절트 객체를 반환한다.

    • value: yield된 값
    • done: 제너레이터 함수가 끝까지 실행되었는지 나타내는 불리언 값
    function* genFunc()  {
      yield 1;
      yield 2;
    }
    
    const generator = genFunc();
    
    console.log(generator.next());    // {value: 1, done: false}


4. 제너레이터 함수의 동작

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

const generator = genFunc();

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}

위의 코드를 살펴보면,

  • 제너레이터 함수는 제너레이터 객체를 반환하기 때문에 변수에 할당할 수 있다.
  • 제너레이터 객체는 그 다음 yield 표현식으로 넘어갈 수 있는 next 메서드를 갖는다.
  • next 메서드는 이터레이터 리절트 객체({value, done})을 반환한다.
    • value 프로퍼티에는 yield 표현식에서 yield된 값이 할당된다.
    • done 프로퍼티에는 제너레이터 함수가 끝까지 실행되었는지를 나타내는 불리언 값이 할당된다.
    • 만약 끝까지 실행된 후에 next 메서드를 호출하면 value에는 제너레이터 함수의 반환값(return 값)이 할당되고, done에는 끝까지 실행되었다는 의미의 true가 할당된다.
generator.next() -> yield -> generator.next() -> yield -> ... -> generator.next() -> return


5. 제너레이터 활용

5.1. 이터러블 구현

  • 제너레이터 함수를 활용하면 이터러블을 구현할 수 있다.
  • 대표적으로 무한 피보나치 수열을 구현할 수 있다.
const fibonacci = (function* () {
  let [pre, cur] = [0, 1];
  
  while(true) {
    [pre, cur] = [cur, pre + cur];
    yield cur;
  }
}());

for (const num of fibonacci) {
  if (num > 10000) break;
  console.log(num);    // 1 2 3 ... 6765
}

5.2. 비동기 처리

  • 제너레이터 함수는 next 메서드와 yield 표현식을 통해 함수 호출자와 함수의 상태를 주고받을 수 있다.
  • 이러한 특성을 활용하면 프로미스의 후속 처리 메서드 then/catch/finally 없이 비동기 처리 결과를 반환하도록 구현할 수 있다.



출처

📖 모던 자바스크립트 Deep Dive
🔗https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Iterators_and_generators#generator_%EC%8B%AC%ED%99%94

profile
직접 만드는 게 좋은 프론트엔드 개발자

0개의 댓글