제너레이터(Generator)

Winney·2021년 3월 7일
0
post-thumbnail

❓ redux-saga를 익히고 있는 도중 generator에 대해서 반드시 이해하고 넘어가야 할 것같아서 공부하고 있다.
블로그에 간단히 정리하며 마무리 지을 생각이다.

Generator란?

비동기 작업을 동기적으로 표현하기 위한 방법 중 하나이다.
그 외 Promise, async/await가 있다.

1. 제너레이터는 어떻게 작성할까?

  • function*과 같이 *function 뒤에 붙이면 제너레이터가 된다.
  • 제너레이터 내부에 yield를 입력하면 제너레이터를 중지 및 재개 할 수 있다.
  • next를 통해 제너레이터를 실행할 수 있다.
function* sayHello() {
  console.log('제너레이터 시작')
  yield '안녕';
  console.log('첫번째 yield의 비동기 작업 끝낸 후 실행');
  yield '나는 Winney야'
  console.log('두번째 yield의 비동기 작업 끝낸 후 실행');
  yield '앞으로 잘 지내자'
  console.log('제너레이터 끝');
};

const gen = sayHello();

gen.next(); // 1번
gen.next(); // 2번
gen.next(); // 3번
gen.next(); // 4번

2. 제너레이터의 실행은 어떻게 될까?

작성 방법을 알았으니 제너레이터가 어떻게 실행되는지 파악해야 할 차례이다.
다음은 위의 예시를 실행한 결과이다.

// 1번 gen.next() 실행
'제너레이터 시작'
{ value: '안녕', done: false }

// 2번 gen.next() 실행
'첫번째 yield의 비동기 작업(안녕) 끝낸 후 실행'
{ value: '나는 Winney야', done: false }

// 3번 gen.next() 실행
'두번째 yield의 비동기 작업(나는 Winney야) 끝낸 후 실행'
{ value: '앞으로 잘 지내자', done: false }

// 4번 gen.next() 실행
'제너레이터 끝'
{ value: undefined, done: true }

여기서 중요한 부분은 next를 이용해서 제너레이터를 작성했을 때 해당 제너레이터의 실행은 yield작성한 부분에서 멈춘다는 것이다.

이후 다시 next로 제너레이터를 실행했을 때 이전 yield의 다음 줄에서부터 실행되어 그 다음 `yield에서 제너레이터가 멈추는 것은 반복한다는 것이다.

즉, 위에서 말한 yield를 입력하면 제너레이터를 중지 및 재개 할 수 있다.는 의미의 yield는 코드가 어딘가에서 멈춰서 비동기작업을 하고 해당 작업이 끝나면 다시 제너레이터가 실행 될 수 있게 하는 키워드라는 의미이다.

그리고 위의 실행 결과를 통해 yield는 객체형태로 valuedone을 반환하는 것을 알 수 있다.

  • value : yield실행 결과의 반환 값
  • done: 제너레이터가 완전히 종료되었는지를 확인하는 값

때문에 4번째 gen.next()yield 반환값을 확인하면 { value: undefined, done: true }를 확인 할 수 있다.

이전 3번째 yield가 마지막으로 실행되며 멈춘 다음 줄에서 4번째 gen.next()가 실행되므로 console.log('제너레이터 끝');가 실행된 후 제너레이터가 끝난다.
그렇기에 yield가 없어서 반환값이 없으므로 valueundefined가 나오고 제너레이터는 완전히 종료되었으므로 donetrue가 된다.

3. 제너레이터로 어떤 것들을 표현 할 수 있을까?

제너레이터는 기본적으로 비동기 작업을 동기적으로 표현하므로서 가독성있게 표현하기 위한 것이다. (하지만 난 아무리 봐도 동기적으로 보인다... 물론 비동기 작업이 있다는 것을 알지만.. 😂)

제너레이터로 표현 할 수 있는 것

  • API 호출 : 대표적인 비동기 작업!
  • 자연수 표현하기
    : 개인적으로 자연수 표현한 제너레이터를 보고 나도 모르게 내가 제너레이터를 함수처럼 생각하고 있었던 문제를 알 수있었다!
function* countNaturalNum() {
  let num = 0;
  while(true) {
    num += 1
    yield num;
  }
}

const gen = countNaturalNum()
gen.next(); // { value: 1, done: false }
gen.next(); // { value: 2, done: false }
gen.next(); // { value: 3, done: false }
gen.next(); // { value: 4, done: false }

만약에 함수였다면 무한루프를 돌았을 것이지만 제너레이터를 사용하면서 자연수를 표현할 수 있게 되었다.

4. next에 인자를 넣으면 어떻게 될까?

예시와 결과가 나오는데 예시만 보고 꼭 결과를 예측해볼 것

  • next의 문법 : gen.next(value)
  • next에는 매개변수가 있고 value는 제너레이터에 전달된다.

그리고 이미 배웠다시피 nextvaluedone 프로퍼티를 가진 객체를 반환한다.

1번 예시

function* getArg() {
  while(true) {
    let value = yield null;
    console.log(value);
  }
}

const gen = getArg()
gen.next(1); // 1번
gen.next(2); // 2번

1번 예시의 결과는 어떻게 나올까?

// 1번
{ value: null, done: false }

// 2번
2
{ value: null, done: false }
  • 1번의 경우 : yield null에서 멈추었기 때문에 yield의 결과인 nullvalue: null로 나타났다.
  • 2번의 경우 : 첫번째 yield 다음 줄부터 실행되기 때문에 console.log(value)가 실행된다. 당연히 next(2)에서 2가 인자로 들어갔기 때문에 2가 출력되고 while반복문이기에 다시 돌아가서 yield null이 실행되어 value: null가 나타난다.

2번 예시

function* getArg() {
  returnedYield = yield 'foo';
  yield returnedYield;
}

const gen = getArg()
gen.next(1); // 1번
gen.next(2); // 2번

2번 예시의 결과는 어떻게 나올까?

// 1번
{ value: 'foo', done: false }

// 2번
{ value: 2, done: false }

제너레이터를 익히며 제일 어려웠던 부분이다!!

💥 중요
분명 gen.next(1)에서 1을 전달했는데 왜 value'foo'로 나올까?
returnedYield는 어디로 갔나?

  • mdn yield 문법 : [rv] = yield [expression];
    여기서 중요한 부분은 [expression]이다. 우리가 알아야 할 것은 next(value)에서 저 value 매개변수가 yield에게 전달되고 그 자리가 [expression] 자리라는 것이다. (yield오른쪽)
    때문에 gen.next(1);를 통해서 1yield 'foo'에 전달하므로서 yield 1되었다.
    하지만 yield 1returnedYield에 전달되는 것은 다음 yield가 실행될 때이다.
    그렇기에 1번 결과에서 우리는 value: 'foo'를 확인 할 수 있고 2번결과에서는 이미 next(2)를 통해 yield2value로 가진 상황에서 returnedYield를 반환하게 되므로 { value: 2, done: false }과 같은 결과가 나온 것이다.

참조 StackOverFlow : https://stackoverflow.com/questions/37354461/how-does-generator-next-processes-its-parameter

개인적으로 next에 인자를 전달한 값을 예측하는게 제일 어려운 부분이었다.
iteratoriterable에 관해서도 작성하고 싶지만 다음에 전반적으로 다루어 보도록 하고 제너레이터에 관한 내용을 마무리한다,

profile
프론트엔드 엔지니어

0개의 댓글

관련 채용 정보