모래블로그

[JavaScript] Generator(제너레이터) 본문

Language/JavaScript

[JavaScript] Generator(제너레이터)

별모래 2024. 2. 16. 18:03
728x90

 

1. Generator(제너레이터)

Generator는 일반적인 함수가 끝까지 실행되고 return 되는 것과는 달리, 중간에 실행을 멈췄다가 다시 접근할 수 있는 특이한 형태의 함수이다.

 

Generator 함수는 나중에 다시 접근하기 위해 context(즉 변수값)를 저장된 상태로 남겨둔다.

Generator는 주로 Promise 와 결합하여 사용되며, 콜백 지옥 같은 비동기 프로그래밍의 문제점들을 많이 완화시켜준다.

 

 

2. Generator 함수 사용

Generator 함수는 function* 키워드를 사용한다.

function* generator1() { ... }

const generator2 = function* () { ... }

 

Generator함수는 화살표 함수를 사용할 수 없다.

 

별표 * (asterisk) 의 위치는 function 키워드와 함수 이름 사이면 아무데나 붙여도 되지만, 일관성 유지 목적으로 function 키워드 바로 뒤에 붙이는 것이 권장된다고 한다.

 

3. 일반함수 vs Generator 함수

일반함수

function sayHi() {  
    return 'hi';  
    return 'hello'; // was never executed
}

 

위 함수를 실행시킬 경우 첫번 return 문인 return 'hi' 를 만나자마자 함수의 실행이 종료될 것이다.

따라서 return 'hello' 는 실행되지 않는다.

 

Generator 함수

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

const generator = sayHiGenerator();
console.log(generator); // { [Iterator] } -> generator object

 

Generator 함수는 함수 키워드 뒤에 * 문자가 붙는 형태이고, 함수 내부에 yield라는 키워드가 사용된다.

yield 와 return의 차이점은 return은 한 번만 실행되지만, 제너레이터 함수의 yield는 여러번 실행된다는 것이다. 

yield 구문은 제너레이터의 실행을 멈췄다가 다음에 다시 시작할 수 있게 만든다.

 

Generator 함수는 호출되더라도 함수의 body를 즉시 실행되지 않고, 대신 함수의 iterator 객체를 반환한다.

 

console 창에 console.dir(generator) 를 찍어보면 제너레이터 객체를 반환하는 것을 알 수 있다.

 

 

이 제너레이터 객체는 iterable 이면서, iterator인 객체이다.

따라서 next 메소드를 호출하기 위해 Symbol.iterator 메소드로 이터레이터를 별도 생성할 필요가 없다.

 

 

반환된 iterator 객체의 next() 메소드가 호출되면 Generator 함수의 body 가 yield expression이 나타날 때까지 실행된다.

 

 

참고로 generator를 for-of 문으로 돌리면 hello, world 까지만 출력된다.

그 이유는 for-of 이터레이션이 done: true일 때 마지막 value를 무시하기 때문이다.

그러므로 for-of를 사용했을 때 모든 값이 출력되길 원한다면 yield로 값을 반환해야한다.

 

 

Generator를 통한 데이터 전달

제너레이터 객체의 next()는 인수를 전달할 수도 있다.

next()를 호출할 때 인수로 값을 지정하면 yield 키워드가 있는 대입문에 값이 할당된다.

function* generator() {
	console.log("start");
    
    const x = yield 1;
    console.log("x = " + x);
    const y = yield (x + 1);
    console.log("y = " + y);
    const z = yield (y + 2);
    console.log("z = " + z);
}

const gen = generator();

console.log(gen.next());

// start
// {value: 1, done: false}

console.log(gen.next(10));
// x = 10
// {value: 11, done: false}

console.log(gen.next(20));
// y = 20
// {value: 22, done: false}

console.log(gen.next(30));
// z = 30
// {value: undefined, done: true}

 

제너레이터의 next 메소드에 인수를 전달하면 제너레이터 객체에 데이터를 밀어넣는다.

 

진행 방식

gen.next() 를 처음 호출하면 첫번 째 yield 를 만나 멈추고, 동시에 yield 뒤의 값을 value로 가져온다.

그래서 콘솔에 찍히는 이터레이터 객체는 { value : 1, done : false } 이다.

 

두 번째로 호출하며 인수로 10을 전달해 주었다. ( console.log(gen.next(10))

전달한 인수는 첫 번째 yield에 할당된다. ( x의 값이 10이 된다.)

실행은 두 번째 yield 를 만나서 멈추고, 동시에 두 번째 yield 뒤의 (x+1)을 value 로 가져오는 순서로 진행이 된다.

 


 

참조 

https://im-developer.tistory.com/193

https://leego.tistory.com/entry/Generator%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C

 

 

 

 

 

 

 

728x90