[JavaScript] 19. Generator

Zero·2023년 2월 13일
0

JavaScript

목록 보기
19/35

Generator

함수의 실행을 중간에 멈췄다가 재개할 수 있는 기능이다.


function* fn() {
 	console.log(1);
  	yield 1;
	console.log(2);
  	yield 2;
  	console.log(3);
  	console.log(4);
  	yield 3;
  	return "finish";
    
}

const a = fn();
  • 다음과 같이 제너레이터 함수는 function 키워드 옆에 * 을 붙여줍니다.

  • yield 키워드 부분에서 함수를 멈출 수 있습니다.

  • a 에는 fn() 실행을 통한 반환된 제너레이터 객체가 담겨져 있고 ,
    제너레이터 함수인 next() 를 통해 결과를 확인해보면

    a.next()
    출력 : 1
    상태 : {value : 1 , done: false} 
    
    a.next()
    출력 : 2
    상태 : {value : 2 , done: false} 
    
    ...
    
    a.next()
    출력 : 
    상태 : {value : finish , done : true} 
  • 이 때 value 는 yield 옆에 붙어 있는 값이고 , done 은 해당 함수가 완료되면 true, 완료되지 않은 경우엔 false 를 리턴합니다.


Generator 함수들

  • next()
  • return()
  • throw()

1) next()

위에서 예제로 설명한것처럼 가장 가까운 함수를 실행해준다

2) return()

next() 함수를 실행하다가 . return("??") 를 실행하면
{value : ?? , done : true} 상태로 변하게 된다.

3) throw()

function* fn() {
  try{
 	console.log(1);
  	yield 1;
	console.log(2);
  	yield 2;
  	console.log(3);
  	console.log(4);
  	yield 3;
  	return "finish";
  } catch(e){
  	console.log(e);
  }
}

const a = fn();

마찬가지로 next() 함수를 실행하다가 throw(new Error('err')) 를 실행하면
{value : undefined , done : true} 상태로 변하게 된다.

iterable

  • 반복이 가능하다라는 의미

Generator 는 iterable 하다.

  • Symbol.iterator 메서드가 있다.
  • Symbol.iterator 는 iterator 를 반환해야 한다.

iterator

  • next 메서드를 가진다
  • next 메서드는 value 와 done 속성을 가진 객체를 반환한다
  • 작업이 끝나면 done 은 true 가 된다.

--> Generator 는 iterator 이면서 iterable 하다

그렇다면 배열이나 문자열은 ??

배열

: 배열 또한 여러 가지 요소가 순차적으로 들어있으므로 iterable 하지 않은가 ?

arr = [1,2,3,4,5] 와 같은 배열이 있다고 하자.
배열을 살펴보면 Symbol.iterator 메서드가 들어있다.
따라서 const it = arr[Symbol.iterator](); 를 사용 하면

it.next()와 같이 iterator 함수를 사용할 수 있다.

따라서 배열과 마찬가지로 Generator 또한

function* fn() {
  	yield 1;
  	yield 2;
  	yield 3;
}

const a = fn();

for (let num of a){
	console.log(num); // 1,  2 , 3
}

다음과 같이 for of 반복문을 이용하여 generator 를 출력할 수 있다.


문자열

: 문자열도 마찬가지로 Symbol.iterator 메서드가 들어있다.
따라서 문자열도 배열이나 generator 처럼 iterable 한 것을 알 수 있다.

next() 에 인수 전달하기

function* fn(){
	const num1 = yield "첫번째 숫자를 입력하세요.";
  	console.log(num1);
  	
  	const num2 = yield "두번째 숫자를 입력하세요.";
  	console.log(num2);
  
  	return num1 + num2; 
  
}

const a = fn();

a.next() 
-> {value : "첫번째 숫자를 입력하세요." , done:false}
a.next(2)
2
-> {value : "두번째 숫자를 입력하세요." , done:false}
a.next(4)
4
-> {value : 6 , done:true}

generator 는 값을 미리 만들어두지 않는다.

generator 는 값을 미리 만들어두지 않고 필요한 순간에만 연산을 하여 값을 주기 때문에 메모리 측면에서 조금 더 효율적이라고 볼 수 있다.

function* fn(){
	let index = 0;
  	while(true) {
    	yield index++;
    }
}

const a = fn();

다음과 같이 무한 반복문에서 제너레이터 함수를 이용하면 필요한 순간에만 계산을 하기 때문에

계산을 하기 직전까지 연산을 미뤄둘 수 있다는 장점이 있다.

yield* 이용하기

function* gen1(){
	yield "W";
	yield "o";
	yield "r";
	yield "l";
	yield "d";
}

function* gen2(){
	yield "Hello,";
  	yield* gen1();
  	yield "!";
}

console.log(...gen2());

--> Hello, W o r l d !

결론

제너레이터는 다른 작업을 하다가 다시 돌아와서 next() 해주면 진행이 멈췄던 부분 부터 이어서 실행합니다.

ex) Redux saga

0개의 댓글