[JavaScript] Generator란 무엇일까?
Front-End/JavaScript

[JavaScript] Generator란 무엇일까?

 

 

 

 

 

Generator👀

 

 

function* generateSequence() {
  yield 1;
  yield 2;
  return 3;
}
  • 일반 함수는 function 키워드로 시작한다면, 제너레이터 함수는 function* 키워드로 시작한다. (화살표 함수는 사용할 수 없다.)
  • 제너레이터 함수 안에는 yield 구문이 존재한다. yield 구문의 문법은 return 구문과 비슷하다. 차이점은 return은 한번만 실행되지만, 제너레이터 함수의 yield는 여러번 실행된다는 것이다. yield 구문은 제너레이터의 실행을 멈췄다가 다음에 다시 시작할 수 있게 만든다.

 

 

제너레이터 함수는 일반 함수와 동작 방식이 다른데, 제너레이터 함수를 호출하면 코드가 실행되지 않고, 제너레이터 객체가 반환된다.

let generator = generateSequence();

 

window console창에 console.dir(generator)를 찍어보면 아래와 같이 제너레이터 객체를 반환하는 것을 알 수 있다.

 

 

 

이 제너레이터 객체는 이터러블(iterable)이면서 동시에 이터레이터(iterator)인 객체이다. 따라서 next 메소드를 호출하기 위해 Symbol.iterator메소드로 이터레이터를 별도 생성할 필요가 없다.

console.log(generator.next());
// {value: 1, done: false}

console.log(generator.next());
// {value: 2, done: false}

console.log(generator.next());
// {value: 3, done: true}

제너레이터 객체의 .next() 메소드를 호출할 때마다, 제너레이터 객체는 스스로 깨어나서 다음번 yield문에 다다를 때까지 실행된다.

 

 

for(let value of generator) {
 console.log(value); // 1, 2
}

참고로 generator를 for-of문으로 돌리면 1, 2까지만 출력된다. 이유는 for-of 이터레이션이 done: true일 때 마지막 value를 무시하기 때문이다. 그러므로 for-of를 사용했을 때 모든 값이 출력되길 원한다면 yield로 값을 반환해야한다.

 

 

 

 

 

 

Generator를 통한 데이터 전달🛵

 

 

이터레이터의 next()와 다르게 제너레이터 객체의 next()는 인수를 전달할 수도 있다.
next()를 호출할 때 인수로 값을 지정하면 yield 키워드가 있는 대입문에 값이 할당된다.

 

 

function* generator(){
    console.log("start");
    const x = yield 1;
    console.log("x="+x);
    const y = yield (x + 1);
    console.log("y="+y);
    const z = yield (y+2);
    console.log("z="+z);
}

const gen = generator();

console.log(gen.next());
// start
// {value: 1, done: false}

console.log(gen.next(10));
// x=10
// {value: 11, done: false}

console.log(gen.next(20));
//y=20
// {value: 22, done: false}

console.log(gen.next(30));
//z=30
// {value: undefined, done: true}

 

이터레이터의 next 메소드는 이터러블의 데이터를 꺼내 온다. 이에 반해 제너레이터의 next 메소드에 인수를 전달하면 제너레이터 객체에 데이터를 밀어 넣는다.

 

위 코드를 이해할 수 있는가?

 

gen.next()를 처음 호출하면 첫번째 yield를 만나 멈춘다. 동시에 yield 뒤의 값을 value로 가져온다. 그래서 console에 찍히는 이터레이터 객체는 {value: 1, done: false} 이다.

 

두번째로 호출하며 인수로 10을 전달해주었다( console.log(gen.next(10)) ). 전달한 인수는 첫번째 yield에 할당된다.( x의 값이 10이된다.) 실행은 두번째 yield를 만나서 멈춘다. 동시에 두번째 yield 뒤의 (x + 1)value로 가져온다. 

 

 

 

 

 

 

Generator와 무한 반복🔁

 

보통의 코드에서 while(true)는 무한 루프에 빠질 위험이 있으므로 사용을 피한다. 하지만 Generator 안에서는 yield로 각 단계의 반복을 제어할 수 있기 때문에, while(true)를 활용하여 무한으로 사용 가능한 로직을 만들 수 있다.

function* getId() {
  let i = 0;
  while(true) {
    yield ++i;
  }
}

const id = getId();

console.log(id.next().value); //1
console.log(id.next().value); //2
console.log(id.next().value); //3

 

 

 

 

 

 

📌

http://hacks.mozilla.or.kr/2015/08/es6-in-depth-generators/
http://hacks.mozilla.or.kr/2016/02/es6-in-depth-generators-continued/