일반 함수를 호출하면 return 문으로 반환값을 리턴하지만 제너레이터 함수를 호출하면 제너레이터를 반환한다. 이 제너레이터는 이터러블이면서 동시에 이터레이터인 객체이다. 다시 말해 제너레이터 함수가 생성한 제너레이터는 Symbol.iterator메소드를 소유한 이터러블이다. 그리고 제너레이터는 next()메소드를 소유하며 next메소드를 호출하면 value,done 프로퍼티를 갖는 이터레이터 객체를 반환하는 이터레이터이다.
//제너레이터 클래스 메소드 classMyClass{ *generatorClsMethod(){ yield1; } } const myClass = new MyClass(); generatorObj = myClass.generatorClsMethod();
3.제너리이터 함수의 호출과 제너레이터 객체
제너레이터 함수를 호출하면 제너레이터 함수의 코드 블록이 실행되는 것이 아니라 제너레이터 객체를 반환한다. 앞에서 살펴본 바와 같이 제너레이터 객체는 이터러블이며 동시에 이터레이터이다. 따라서 next메소드를 호출하기 위해 Symbol.iterator 메소드로 이터레이터를 별도로 생성할 필요가 없다.
next 메소드는 이터레이터 결과 객체와 가티이 value,done이라는 프로퍼티를 갖는 객체를 반환한다.vlaue프로퍼티는 yield문이 실행되었는지를 나타내는 boolean타입의 값이다. 마지막 yield문까지 실행된 상태에서 next메소드를 호출하면 done프로퍼티 값을 true가 된다.
4.제너레이터의 활용
4.1. 이터러블의 구현
제너레이터는 함수를 사용하면 이터레이션 프로토콜을 준수해 이터러블을 생성하는 방식보다 간편하게 이터러블을 구현할 수 있다. 이터레이션 프로토콜을 준수하여 무한 피보나치 수열을 생성하는 함수를 구현해 보겠다.
function* gen(n){ let res; res = yield n //n:0<= gen함수에 전달한 인수 console.log(res) //res:1 <= 두번째 next 호출 시 전달한 데이터 res = yield res; console.log(res) //res:2 <= 세번째 next 호출 시 전달한 데이터 res = yield res; console.log(res); // res: 3 ⟸ 네번째 next 호출 시 전달한 데이터 return res; }
const generatorObj = gen(0);
console.log(generatorObj.next()); // 제너레이터 함수 시작 console.log(generatorObj.next(1)); // 제너레이터 객체에 1 전달 console.log(generatorObj.next(2)); // 제너레이터 객체에 2 전달 console.log(generatorObj.next(3)); // 제너레이터 객체에 3 전달
functiongetUsers(genObj,username){ fetch(`https://api.github.com/users/${username}`) .then(res =>res.json()) //1.제너레이터 객체에 비동기 처리 결과를 전달한다. .then(user=> genObj.next(user.name)); } //제너레이터 객체 생성 const g =(function* (){ let user; //2.비동기 처리 함수가 결과를 반환한다. //비동기 처리의 숭성가 보장된다. user = yield getUser(g,'kim'); console.log(user); // user =yield getUser(g,'lee'); console.log(user); user = yield getUser(g,'park'); console.log(user); }());
//제너레이터 함수 시작 g.next();
1.비동기 처리가 완료되면 next메소드를 통해 제너레이터 객체에 비동기 처리 결과를 전달한다. 2.제너레이터 객체에 전달된 비동기 처리 결과는 user 변수에 할당한다. 제너레이터를 통해 비동기 처리를 동기 처럼 구현 할 수 있으나 코드는 장황해졌다. 따라서 좀더 간편하게 비동기 처리를 구현할 수있는 async/await가 es7에 도입되었다.