본문 바로가기
WEB/깊게 공부하기

[JS] generator 살펴보기 - Generator 2

by IT황구 2023. 10. 17.
728x90
반응형

Generator 1편과 이어서 보신다면 더 좋습니다.

https://rbals0445.tistory.com/142

 

[JS] iterable, iterator 살펴보기 - Generator 1

안녕하세요! 오랜만에 기술 포스트를 작성하네요. 이번 글은 시리즈처럼 작성될 예정입니다. babel이 Generator를 transpile한 코드를 이해하고, 어떻게 작동하는지 이해하기 위해 필요한 지식들을 미

rbals0445.tistory.com

 

지난 글에서 Iteration protocol에 대해서 알아봤습니다.

이번 글에서는 generator에 대해서 소개합니다.  제너레이터 사용법, 메소드같은 기초적인 내용들은 mdn 같은 문서를 참고 부탁드립니다.

정의

"코드 블럭의 실행을 멈췄다가 다시 실행할 수 있는 특수한 형태의 함수"

 

JS Deep Dive에도 나오는 설명인데 정말 적절하게 설명한것 같습니다.

일반적으로 함수를 호출하면 내부의 코드가 실행이 되지만, 원할때 직접 하나씩 실행할 수 있게끔 iterator를 반환해줍니다.

 

왜 나왔을까?

iterator protocol을 확인 했을때 generator를 한 번이라도 보셨던 분들은 익숙함을 느끼셨을 것입니다.

매번 순회를 위해 iteration protocol을 정의 하는것은 쉽지 않습니다. 또한 에러에도 취약합니다.

generator는 이것을 손쉽게 해결해 줍니다.  

 

function *(){} 형태의 선언과 yield만 있으면 [Symbol.iterator]()~~, next() 같은 함수들을 직접 구현하지 않아도 됩니다.

 

특징

generator 함수를 호출하면 코드를 실행하지 않고 `Generator`라고 불리는 `iterator`를 반환합니다.

iterator protocol을 구현했기 때문에 next 같은 함수들도 가지고 있습니다.

그리고 iterator는 그냥 iterator가 아닙니다. `iterable iterator` 의 형태여야 합니다. 꼭 그래야 하는 이유가 있습니다.

 

iterable iterator

iterable iterator는 공식 명칭은 아닙니다. mdn에서 [@@iterator] method가 자기 자신(this)을 반환할 때 iterable iterator라는 명칭을 사용합니다.

 

왜 매번 새롭게 iterator를 반환하지 않고, 자기 자신을 반환해야 할까요?

자기 자신을 반환하지 않고, 매번 새롭게 iterator 반환이 필요한 경우는 언제일까요?

 

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols

 

Iteration protocols - JavaScript | MDN

Iteration protocols aren't new built-ins or syntax, but protocols. These protocols can be implemented by any object by following some conventions.

developer.mozilla.org

지난 글에서 custom iterator를 정의하는 코드에 대해서 봤습니다.

 

매번 새롭게 iterator를 반환하는 경우

const customObj = {
  [Symbol.iterator]() {
    return {
      count:0,
      next(){
        if(this.count > 3) {
          return {done: true, value: this.count}
        }
        
        return {done: false, value: this.count++};
      }
    }
  }  
}

for(const val of customObj) {
  console.log(val) // 0,1,2,3
}

for(const val of customObj) {
  console.log(val) // 0,1,2,3
}

@@iterator method에서 매번 새로운 iterator를 반환하고 있습니다.

 

첫번째 for...of 정상 동작

두번째 for...of 정상 동작

 

다음 방식을 확인해 보겠습니다.

 

자신의 iterator를 반환하는 경우

const customObj = {
  count:0,
  [Symbol.iterator](){
     console.log("Symbol.iterator");
     return this;
  },
  next(){
    if(this.count > 3) {
      console.log("fin")
      return {done: true, value: this.count}
    }
    
    return {done: false, value: this.count++};
  }
  
}
// Symbol.iteartor
for(const val of customObj) {
  console.log(val) // 0,1,2,3
}
// fin

// Symbol.iteartor 
for(const val of customObj) {
  // fin
  console.log(val);
}

이번에는 @@iterator method에서 this를 반환하고 있습니다.

첫번째 for...of도 정상으로 작동해서 문제가 없어보입니다.

 

두번째 for...of ???

하지만 두번째 for..of가 이상합니다.

customObj 안에 있는 count값이 계속 유지가 되므로, 두번째 for..of는 `{done:true ~~}`로 인해 실행되지 않습니다.

 

매번 새로운 iterator를 반환하는 경우 자기 자신을 반환하는 경우
Array, Map, ...  Generator
여러번 순회될 수 있다. 딱 한번만 순회된다.

여러번 순회될 수 있는 경우에는 매번 새로운 iterator를 반환해야 합니다.

Generator처럼 한번만 순회되어야 하는 경우 자기 자신을 반환해야 합니다. 그렇지 않으면 예상과 다른 결과가 생기게 됩니다.

 

Generator가 iterable iterator가 맞는지 확인하기

매번 새로운 iterator를 반환하는 것, 자기 자신을 반환할때의 차이를 알게 되었습니다.

그러면 generator는 자기 자신을 반환하는지 어떻게 확인할 수 있을까요?

 

1. for...of에 돌려보기

 

사진을 확인하면 두번째 for...of가 console에 값이 찍히지 않고 넘어가는 것을 볼 수 있습니다.

 

2. 리턴하는 iterator가 자기 자신과 같은지 확인하기

 

generator는 @@iterator method가 반환하는 iterator가 동일합니다.

하지만 Array처럼 매번 순회할 수 있는것은 새로운 iterator를 반환하는 것을 알 수 있습니다.

 

어떻게 사용할 수 있을까?

1. generator를 사용하면 "지연 평가"를 할 수 있습니다.

지연 평가의 장점은 필요할때 실행하고, 메모리를 생성해서 효율성을 높일 수 있습니다.

 

2. Babel은 async, await를 제너레이터를 통해서 구현하고 있습니다. (이 부분도 추후 다룰 예정입니다)

이 부분을 확인하면 await을 사용할때 왜 try, catch가 필요한지 알게 됩니다.

 

2번을 구현할때 제너레이터의 아이디어가 들어가는것 부터가 얼마나 중요한 것인지 알 수 있습니다. 

 

마치며

이번 글에서는 다음 내용들을 다뤘습니다.

 

1. generator의 정의, 필요성, 특징

2. generator가 iterable iterator 이어야 하는 이유

3. generator가 iterable iterator가 맞는지 확인하는 방법 (다른 iterable object와의 차이)

4. 어떻게 사용할 수 있을까?

 

지금까지 쓴 모든 내용이 다음 글을 위한 빌드업 이었습니다.

 

Generator가 나오기 전 facebook에서 이미 generator polyfill을 만들었습니다.

 

호출마다 매번 다른값을 반환하는 것을 어떻게 했을까요..??

ECMAScript의 draft 스펙 문서를 보고 구현했는데, 정말 대단합니다. 배울점이 많아서 다음번에 포스팅 하도록 하겠습니다. 

 

 

감사합니다.

 


https://rbals0445.tistory.com/144 (3편 보기)

 

[JS] generator polyfill regenerator 살펴보기 - Generator 3

[JS] generator 살펴보기 - Generator 2 [JS] generator 살펴보기 - Generator 2 Generator 1편과 이어서 보신다면 더 좋습니다. https://rbals0445.tistory.com/142 [JS] iterable, iterator 살펴보기 - Generator 1 안녕하세요! 오랜만

rbals0445.tistory.com

 

728x90
반응형