#Javascript 제너레이터

Jinmin Kim·2020년 12월 10일
0

Generator

Generator란?

Javascript의 Generator는 function*으로 정의된 함수를 호출하여 얻어지는 객체. Generator 객체는 iterable & iterator이다 이러한것들은 for of에 사용이 가능하며 직접 next()함수를 사용할수있게 해준다.

iterable? :

반복 가능한 객체라는것으로 아래의 생성자를 만들어낼때에
iterable 객체가 만들어지게된다.

  • String
  • Array
  • Map
  • Set

Generator 사용 방법

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);

Generator Iterator

제너레이터는 일반적으로 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);
  })
profile
Let's do it developer

0개의 댓글