Fronted/JavaScript

[JavaScript] Generator(제너레이터) 개념 및 키워드 정리 ( * / yield / next)

성코 2023. 9. 18. 18:22

1. Generator란?

2. Generator 키워드 [ * / yield / next ]


Generator란?

제너레이터 함수는 일반함수와 달리 중간에 실행을 멈추거나, 멈춘 자리에서 다시 실행되게 할 수 있는 함수를 말한다. 

 

아래와 같이 작성한 코드의 일반함수는 계속 호출해도 무조건 1을 반환한다.

//일반함수
function number() {
	//...
    return 1;
    return 2; //was never executed
    return 3; //was never executed
}

한 번의 실행으로 함수의 끝까지 혹은 return까지 실행되는 일반함수와 달리,

제너레이터 함수를 이용하면 사용자의 요구에 따라 함수의 실행(일시정지, 다시 시작)을 조절할 수 있다. 

 

yield라는 키워드를 사용하면 해당 라인까지만 코드를 실행하고, 뒷부분은 다시 실행을 요청할 때까지 실행하지 않게함으로써 비동기처리를 할 수 있게 한다. 제너레이터는 나중에 다시 시작하기 위해서 변수값을 저장된 상태로 남겨둔다. 주로 promise와 결합하여 사용되고, 콜백지옥같은 비동기 프로그래밍 문제점들을 완화시켜준다. 

 


제너레이터 함수를 만들기 위해서는

  1.  function*이라는 키워드를 사용한다.
  2. 함수 내부에 return 외에도 yield를 사용할 수 있다. (제너레이터를 멈추거나 다시 실행시킴)
  3. 값을 호출하고 파라미터로 전달하기 위해 next() 메소드를 사용한다.

제너레이터 키워드 [ * ]

제너레이터 함수임을 구분하기 위해 function 키워드 바로 다음에 astrok(*)을 붙인다.  

function* helloWorld(params){
    yield 'hello';
    yield 'world';
    return 'helloWorld';
}

제너레이터 키워드 [ yield ]

yield는 "산출하다"라는 의미로, 제너레이터를 멈추거나 다시 실행하는데 사용된다.

제너레이터 함수에서는 yield 키워드가 있을 때까지, yield 키워드를 기준으로 코드가 잘려서 실행된다. 따라서 yield 전에 있는 평가문들의 실행을 멈출 수 없다. 함수는 잘린 상태로 정지해있다가 다시 이 함수를 시작했을 때 멈췄던 부분부터 실행을 이어서 하고, 다음 yield를 만날 때까지 쭉 실행된다. 

 

아래와 같이 표현식으로 작성할 경우, 왼쪽에 결과값을 할당한다. 

const userid = yield "id0303";

제너레이터 키워드 [ next ]

next() 메소드를 호출하면 yield 키워드를 만나기 전까지 함수가 실행된다. yield 키워드를 만나면 일시중지하고 생성된 값을 반환한다. 다시 next() 메소드를 호출하면 일시중지된 위치에서부터 다음 yield를 만날 때까지 실행을 재개한다. 

function* helloWorld(params){
    yield 'hello';
    yield 'world';
    return 'helloWorld';
}

const result = helloWorld();
console.log(result.next()); // { value: 'hello', done: 'false'}
console.log(result.next()); // { value: 'world', done: 'false'}
console.log(result.next()); // { value: 'helloWorld', done: 'true'} --> 함수종료
console.log(result.next()); // { value: undefined, done: 'true'} --> 반환값 없음, 함수종료

 

next 함수를 실행하면 { value, done } 이라는 데이터를 반환한다. value반환값이고, done은 제너레이터 함수가 가장 마지막 값을 yield 했는지 여부를 boolean 값으로 나타낸 것을 의미한다. 만약 반환할 값이 없다면 value값은 undefined를 반환한다. 


next() 메소드 안에 인자를 넣어 호출하면, 진행을 멈췄던 위치의 yield를 인자값으로 교체하고 그 위치에서 다시 실행한다. 

function* test() {
  yield 1;
  const val = yield 2;
  const final = yield 3;
  const ex = yield 50;
  return final;
}

const result = test();
console.log(result.next()); // { value: 1, done: false }
console.log(result.next()); // { value: 2, done: false }
console.log(result.next(100)); // { value: 3, done: false }, val = 100
console.log(result.next(99)); // { value: 50, done: true }, final = 99
console.log(result.next()); // { value: undefined -> 99, done: true }

 

  1. 첫번째 next() 호출시 value가 1인 객체가 리턴된다.
  2. 두번째 next() 호출시 value가 2인 객체가 리턴된다. 
  3. 세번째 next() 호출시 value가 3인 객체가 리턴되며 실행을 멈춘다. 그리고 인자로 들어간 100이 이전에 멈췄던 지점인 val에 할당된다.
  4. 네번째 next() 호출시 value가 50인 객체가 리턴되며, 인자로 들어간 99가 이전에 멈췄던 지점인 final에 할당된다. 
  5. 마지막 next() 호출시 final을 리턴하므로 value가 99인 객체가 리턴된다. 

배열을 반복하는 for ~ of 문법을 사용해서 call() 함수 내에서 yield를 차례로 호출할 수 있다. 

function* test() {
  yield 1;
  const val = yield 2;
  const final = yield 3;
  const ex = yield 50;
  return final;
}

const result = test();

for (let data of test()) {
  console.log(data); //1, 2, 3, 50
}