제네레이터

devAnderson·2022년 4월 14일
0

TIL

목록 보기
88/103

🚍 0. 작성 이유

이번에 redux-saga와 관련된 개념을 공부하기 위해 미리 선 지식으로 필수적으로 알아야 할 제네레이터의 개념을 공부하여 정리하는 글이다.
현재 redux-toolkit으로 redux팀조차 공식적으로 추천할만큼 많이 해당 툴이 애용되는 시기점이기도 하지만, 아직 기존 코드들에 redux-saga를 쓰는 일이 비일비재하므로 해당 코드를 이해하기 위해서라도, 알고는 있어야 한다.

🚍 1. 제네레이터?

제네레이터는 함수이다. 하지만 이 함수는 일반함수와는 아주 다른 점이 존재한다. 그것은 바로

개발자가 함수의 body 블록이 어디까지 실행될지를 컨트롤이 가능한 함수

라는 점이다.

예를들어, 일반 함수는 매개변수로 인자를 받아 내부에 정의하면서 실행 컨텍스트를 형성해 return문을 만나기 전까지 모든 코드를 실행한다.

function noralFunc (a, b) {
   const value1 = a + b;

   return value1
}
// 일반 함수를 호출하면 해당 코드블록까지 모든 문들이 실행된 후 결과를 리턴한다. 즉, 개발자가 코드블록의 실행 단계를 컨트롤할 수 없다.

하지만 제네레이터 함수는 자신의 코드 블록을 "yield" 라는 단위를 기반으로 하여 실행하는 것이 가능하다.

우선 제네레이터 함수를 호출하게 되면 "제네레이터 객체" 를 리턴한다.

  1. 이 제네레이터 객체는 [[prototype]]의 Generator.prototype 메서드로 "next"라는 메서드를 포함하고 있는 이터레이터이다. ( 이터레이터의 정의)
  2. 또한, 제네레이터 객체는 내부에 [Symbol.iterator] 메서드를 상속받는 이터러블이다 (이터러블의 정의. 이터러블은 즉 객체를 for문과 같은 순환 명령문으로 순회가 가능하다는 것을 의미한다)

형태는 es6에 같이 업데이트된 Promise 생성자가 리턴하는 프로미스객체와 매우 유사한 형태를 가지고 있다.

이 제네레이터 객체가 리턴되는 시점까지는 제네레이터 함수 몸체의 어떤 코드도 실행되지 않고,
단지 리턴된 제네레이터 객체 내의 [[scopes]] 슬롯 부분에 제네레이터 함수가 호출될 당시의 스코프 체인에 해당하는 내용을 담아둔 채로 "suspended" 상태가 된다.

그 후, next를 호출하면 해당 [[generatorState]] 부분이 "running" 으로 변경되면서 해당 [[scopes]] 슬롯에 보유하고 있던 실행 컨텍스트 내용을 콜스텍에 집어넣으며 함수의 실행을 시작하는데, 이때 마주치는 yiled까지의 코드블록을 실행하여 초기화 등을 수행한 후 해당 실행컨텍스트를 다시 제네레이터 객체의 [[scopes]]에 되돌린 뒤 과정을 마친다. {value, done} 을 담은 객체를 리턴하며 과정을 종료한다.

function* generatorFnc () {
  let name = "hello"
  yield name;

  let age = 2;
  yield age;

  let description = "yes mama"
  yield description;
}

const generator = generatorFnc();
const value1 = generator.next(); // {value: 'hello', done: false}
const value2 = generator.next(); // {value: 2, done: false}
const value3 = generator.next(); // {value: 'yes mama', done: false}
const value4 = generator.next(); // {value: undefined, done: true}

추가적으로
제네레이터 객체 내부에 존재하는 [[prototype]] 슬롯의 Generator.prototype 내부에는 실행과 관련한 next 메서드 뿐만 아니라, 도중에 이후의 yield 까지를 무시하고 인자로 받아들이는 값을 value로, done을 true로 할당한 객체를 리턴한 뒤 제네레이터 함수의 모든 코드블록을 완료시키는 "return" 메서드와, 반대로 throw Error을 발생시키면서 value에 undefined와 done으로 true를 할당한 객체를 리턴한 뒤 제네레이터 함수의 코드블록을 종료시키는 throw 메서드도 있다.

function* generatorFunc () {
    try{
     yield 1;
     yield 2;
     yield 3;
    } catch(e){
     console.error(e);
    }
}

const generator = generatorFunc();
//return 메서드 호출 시, 제네레이터 함수 종료
console.log(generator.return("finish")) // {value: 1, done: true}

// throw 메서드 호출 시, 제네레이터 함수 종료 
console.log(generator.throw("에러발생")) // {value:undefined, done: true}
profile
자라나라 프론트엔드 개발새싹!

0개의 댓글