Redux-Saga를 공부하면서 Generator이라는 문법을 알게 되었는데, 이에 대해 확인해 보려고 한다.
개요
A generator is a process that can be paused
and resumed and can yield multiple values.
(Generator는, 일시 정지 및 다시 시작할 수 있고 여러 값을 생성할 수 있는 프로세스다.)
직접 해보기
Generator은 함수와 비슷하게 생겼는데, 동작 방식이 다르다.
// function 뒤에 *가 붙는다.
function* myGenerator() {
console.log('시작!');
yield 1;
console.log('hello!');
yield 2;
console.log('world!');
return 3;
}
// 실행하면 이상한 결과값이 튀어나옴
const gen = myGenerator();
console.log(gen); // myGenerator {<suspended>}
여기에서 next() 메서드가 중요한데, 이 함수를 호출하면 가장 가까운 yield <value> 문을 만날 때까지 실행이 지속되며, 이후 yield <value> 문을 만나면 실행이 멈추고 value가 반환된다.
console.log('1트:: ', gen.next()); // {value: 1, done: false}
console.log('2트:: ', gen.next()); // {value: 2, done: false}
console.log('3트:: ', gen.next()); // {value: 3, done: true}
console.log('4트:: ', gen.next()); // {value: undefined, done: true}
console.log('5트:: ', gen.next()); // {value: undefined, done: true}
/** Result------
* 시작!
* 1트:: {value: 1, done: false}
* hello!
* 2트:: {value: 2, done: false}
* world!
* 3트:: {value: 3, done: true}
* 4트:: {value: undefined, done: true}
* 5트:: {value: undefined, done: true}
*/
이 next()를 보면 알 수 있듯 Generator는 Iterable객체로서, for문을 적용할 수 있다.
// 이렇게 호출하면 .value에 접근할 필요 없이 바로 데이터가 나온다!
for(const value of gen){
console.log(value);
}
/** Result------
* 시작!
* 1
* hello!
* 2
* world!
*/
근데 여기서 3이 출력되지 않았는데, iteration이 done: true 일때 마지막 값이 나오지 않기 때문이다. 때문에, 모든 값이 나오게 하려면 return대신 yield로 변경해야 한다.
function* myGenerator() {
console.log('시작!');
yield 1;
console.log('hello!');
yield 2;
console.log('world!');
yield 3; // return 3 yield로 변경
}
next에 값 넣기
next() 호출 시 인자를 전달하여 제너레이터 함수 내부에서도 사용할 수 있다.
function* addNum() {
console.log('a를 입력해주세요.');
const a = yield;
console.log('b를 입력해주세요.');
const b = yield;
yield a + b;
}
const calc = addNum();
console.log('1트::', calc.next());
console.log('2트::', calc.next(1));
console.log('3트::', calc.next(3));
console.log('4트::', calc.next());
/** Result------
* a를 입력해주세요.
* 1트:: {value: undefined, done: false}
* b를 입력해주세요.
* 2트:: {value: undefined, done: false}
* 3트:: {value: 4, done: false}
* 4트:: {value: undefined, done: true}
*/
에러 떤지기
에러 처리는 throw()메서드를 이용하여 처리할 수 있다. 에러를 처리하면, Done 처리 된다.
function* throwError() {
try {
yield 1;
yield 2;
return 3;
} catch(err) {
console.log('에러 발생!', err);
}
}
const errTest = throwError();
console.log('1트::', errTest.next());
console.log('2트::', errTest.throw('에러 내용입니다'));
console.log('3트::', errTest.next());
/** Result------
* 1트:: {value: 1, done: false}
* 에러 발생! 에러 내용입니다
* 2트:: {value: undefined, done: true}
* 3트:: {value: undefined, done: true}
*/
참고 자료
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Generator
https://www.digitalocean.com/community/tutorials/understanding-generators-in-javascript
https://ko.javascript.info/generators