Javascript의 Generator는 function*으로 정의된 함수를 호출하여 얻어지는 객체. Generator 객체는 iterable & iterator이다 이러한것들은 for of에 사용이 가능하며 직접 next()함수를 사용할수있게 해준다.
반복 가능한 객체라는것으로 아래의 생성자를 만들어낼때에
iterable 객체가 만들어지게된다.
yield : 멈추는 곳
next : 다음으로 넘어가기
Generator의 다른 객체와 다른점은 1회 이상/실행을 거듭할수있으면서도 반드시 끝까지 실행해야 할필요는 없는 특별한 함수이다.
function* foo() {
console.log(yield)
console.log(yield)
console.log(yield)
}
let g = foo()
g.next() // start generator
g.next(1)
g.next(2)
g.next(3)
------------------------------
//for.. of 루프는 매번 자동으로 next()를 호출하다가
done:true를 받으면 그자리에서 멈추게된다.
function* foo() {
yield 1
yield 2
yield 3
}
// foo()로 생성된 제너레이터를 순회하며 값을 읽어간다.
for (let i of foo()) {
console.log(i)
}
code 출처: https://medium.com/@jooyunghan/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EC%A0%9C%EB%84%88%EB%A0%88%EC%9D%B4%ED%84%B0%EC%9D%98-%EC%9E%AC%EB%AF%B8-246553cadfbd
Generator의 객체는 어떻게 나타날까?
function *foo(x){
var y = x * (yield);
return y;
}
var it = foo(6);
it.next();
var res = it.next(7);
console.log(res);//{ value: 42, done: true }
res.value;
value 값은 그때의 yield에서 리턴된 값, done의 값은 이 Generator 객체가 끝낫는지의 여부가 false, true로 나타나게된다.
function *foo(x){
var y = x * (yield "hello");
return y;
}
var it = foo(6);
var res = it.next()
console.log("res", res); //res { value: 'hello', done: false }
console.log(res.value); //hello
res = it.next(7);
console.log("res", res); //res { value: 42, done: true }
console.log(res.value); //42
제너테이터를 여러개 사용할경우는 어떻게 될까?
function *foo(){
var x = yield 2;
z++;
var y = yield (x * z);
console.log(x, y, z);
}
var z = 1;
var it1 = foo();
var it2 = foo();
var val1 = it1.next().value;
var val2 = it2.next().value;
console.log("val1",val1);
console.log("val2",val2);
val1 = it1.next(val2 * 10).value;
val2 = it2.next(val1 * 5).value;
console.log("val1",val1);
console.log("val2",val2);
it1.next(val2 / 2);
it2.next(val1 / 4);
제너레이터는 일반적으로 break, return 또는 잡히지 않은 예외로 인해 비정상 완료로 되면 제너레이터의 이터레이터를 중지하도록 신호를 주게된다.
function *something(){
try{
var nextVal;
while (true){
if(nextVal === undefined){
nextVal = 1;
}
else{
nextVal = (3 * nextVal) + 6;
}
yield nextVal;
}
}finally{
console.log("정리 완료!")
}
}
for( var v of something()){
console.log(v);
if(v > 500){
break;
}
}
이때의 for of문의 break;를 만나게되면 자동적으로 finally로
제너레이터는 이동하게된다.
function *something(){
try{
var nextVal;
while (true){
if(nextVal === undefined){
nextVal = 1;
}
else{
nextVal = (3 * nextVal) + 6;
}
yield nextVal;
}
}finally{
console.log("정리 완료!")
}
}
var it = something();
for(var v of it){
console.log(v);
if(v > 500){
console.log(it.return("Hello World").value);
};
}
또한 return을 사용하여서 수동으로 제너레이터의 인스턴스를 멈추게 할수도있다.
동기적 에러처리 효과
function *main(){
var x = yield "Hello World";
console.log(x);
}
var it = main();
var a = it.next();
console.log(a.value)
try{
it.throw("허걱");
}catch(err){
console.error(err);
}
function foo(){
var a = $.ajax({
url: 'http://localhost:3000/single-json',
type: 'GET'
});
console.log("a",a)
return a;
}
function *main(){
try{
var text = yield foo();
console.log("text",text);
}
catch(err){
console.error("err",err);
}
}
var it = main();
var p = it.next().value;
console.log("p", p);
p.then(
function(text){
it.next(text);
},
function(err){
it.throw(err);
})