본문으로 바로가기

TIL 2023-02-07 Generator

category TIL 2023. 2. 7. 00:59

Protobuf 라이브러리인 pbkit을 보다가 제너레이터 문법이 사용되는 부분이 있다.(사실 많음)

 

https://github.com/pbkit/pbkit/blob/6f905bb831fd30f7346ad04ff568537dc9445c93/codegen/ts/index.ts#L141

 

GitHub - pbkit/pbkit: Protobuf toolkit for modern web development

Protobuf toolkit for modern web development. Contribute to pbkit/pbkit development by creating an account on GitHub.

github.com

 

제너레이터 문법은 리덕스 사가 쓸떄 아주 겉핥기로만 머리에 넣어놨는데 제대로 공부해보자

 

제너레이터 함수는 이터러블을 생성하는 함수다

 

```

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

const gen = customGenerator();
```

 

제너레이터 함수의 리턴값은 제너레이터를 반환하는데, 제너레이터는 iterable이면서 iterator이다. 이 generator는 symbol.iterator를 가지고 있다는 뜻이다.

 

 

iterator는 next 메서드와 {value, done } 속성을 가지고 있는 객체를 의미한다. 그리고 next 함수를 통해 값을 iterate(반복)할 수 있다. 모든 값을 소비하였으면 next 메서드에서 done이 true인 객체를 반환한다.

 

function makeRangeIterator(start = 0, end = Infinity, step = 1) {
  let nextIndex = start;
  let iterationCount = 0;

  const rangeIterator = {
    next() {
      let result;
      if (nextIndex < end) {
        result = { value: nextIndex, done: false };
        nextIndex += step;
        iterationCount++;
        return result;
      }
      return { value: iterationCount, done: true };
    },
  };
  return rangeIterator;
}

const it = makeRangeIterator(1, 10, 2);

let result = it.next();
while (!result.done) {
  console.log(result.value); // 1 3 5 7 9
  result = it.next();
}

console.log("Iterated over sequence of size: ", result.value); // [5 numbers returned, that took interval in between: 0 to 10]

그래서 iterator를 통해서 위와 같이 배열을 iterate할수 있다.

 

그리고 이 이터러블을 간단하게 생성할수 있는것이 제너레이터 문법이다.

 

next 시의 동작을 구현할 필요 없이, yield를 통해서 이를 대체할 수 있다.

 

function* makeRangeIterator(start = 0, end = Infinity, step = 1) {
  let iterationCount = 0;
  for (let i = start; i < end; i += step) {
    iterationCount++;
    yield i;
  }
  return iterationCount;
}

 

 

제너레이터 함수에서는 return시에는 제너레이터 함수를 종료하지만, generator가 try catch안에 있으면 종료되지 않는다. return 이후 finally의 yield가 실행되며 이후 return값의 인자로 값이 종료된다.

 

 

제너레이터 문법으로 가장 많이 나오는 예시는 비동기 프로그래밍인데,

 

//A 작업 - > B 작업 -> C 작업을 해야했을떄


function A(..., function B(..., function C(..., )))

기존의 콜백 함수 형식으로 비동기성을 해결해야했던 문제점을

 


function * resolver(){

yield getEmail();
yield login();
}

제너레이터를 통해 이렇게 해결할 수 있다는 점이다.

 

물론 getEmail 등의 함수에 resolver의 next를 호출하는 코드가 들어가 있어야한다.

 

제너레이터 문법이 ES6에 나왔고, 비동기를 더 우아하게 해결해주는 async await이 다음 문법인 ES7에 나와서 현재 단순 비동기를 짤떄는 굳이 저렇게 짤 이유가 없긴 하지만, 저런 개념에서 리덕스 사가가 나왔다는 것을 알아서 알찼다.

 

빨리 마크다운 형태의 블로그 하고 싶다..