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/