19. generator

자바스크립트의 제너레이터(generator, 생성기)는 함수의 실행을 중간에 멈추고 원하는 시점에 다시 재개할 수 있는 특별한 함수이다. 일반 함수가 실행되면 끝까지 실행된 후 반환값을 전달하는 것과 달리, 제너레이터는 여러 번에 걸쳐 값을 나누어 산출한다. 이 기능을 통해 이터러블(iterable, 순회 가능한 객체)이자 이터레이터(iterator, 반복자) 객체를 손쉽게 생성할 수 있다.

제너레이터 함수 실행과 재개 흐름 — 함수 호출로 이터레이터를 생성하고 next() 호출 시마다 yield 지점까지 실행한다.

1. 특징

제너레이터는 순회 가능한 이터레이터를 생성하여 반환하는 함수이다. 일반 함수는 한 번 호출되면 제어권을 넘기지 않고 끝까지 실행을 마치지만, 제너레이터는 실행 도중 작업의 일시 정지와 재시작이 가능하며 내부 실행 상태를 스스로 보존한다.

제너레이터의 동작은 일시정지와 재생 버튼이 있는 영상 재생기와 유사하다. 필요한 시점에 한 단계씩 진행시키면서 현재의 코드 실행 위치와 변수 값을 기억하므로, 대용량 데이터를 다루거나 순차적인 상태 관리가 필요할 때 유용하다.

2. syntax

제너레이터 함수는 function* 키워드로 선언하며, 내부에는 함수의 실행을 일시 정지하고 값을 전달하는 yield(일드) 키워드를 반드시 포함한다.

function* gen() {
	yield 1; //포인트1
	yield 2; //포인트2
	yield 3; //포인트3
}
const iter = gen(); // gen()는 호출해도 바로실행되지 않고 이터레이터를 반환함
console.log(iter.next()); //{ value: 1, done: false }
console.log(iter.next()); //{ value: 2, done: false }
console.log(iter.next()); //{ value: 3, done: false }
console.log(iter.next()); //{ value: undefined, done: true }

제너레이터 함수의 yield 키워드는 프로그램의 일시정지 지점 역할을 한다. gen() 함수를 호출하면 내부 코드가 즉시 실행되지 않고 이터레이터 객체만 반환된다.

반환된 이터레이터의 next() 메서드를 호출하면 다음 yield 지점까지 코드가 실행된 후 값을 반환하고 실행을 멈춘다. 이때 next() 메서드는 { value: 값, done: 불리언 } 구조의 객체를 반환한다. value는 yield 뒤에 명시된 표현식의 평가 값이며, done은 함수의 실행이 완료되었는지를 나타낸다. 모든 yield를 지나 함수의 끝에 도달하면 { value: undefined, done: true }가 반환되어 순회가 종료되었음을 알린다.

2-1 yield 의 표현식

제너레이터 객체는 이터러블 규약을 만족하므로 for...of 반복문을 사용하여 산출된 값을 차례대로 순회할 수 있다.

for (var v of iter) console.log(v)

for...of 문은 내부적으로 done이 true가 될 때까지 next() 메서드를 반복 호출하며 value 값을 추출한다. 단, 앞선 코드에서 next()를 호출하여 이미 done: true 상태가 된 이터레이터 객체는 순회할 값이 남아있지 않으므로 반복문이 실행되지 않는다. 다시 순회하려면 제너레이터 함수를 새로 호출하여 새로운 이터레이터 객체를 생성해야 한다.

3. m~n까지의 정수값을 순서대로 꺼내는 iterator 를 생성하는 generator

제너레이터를 활용하면 특정 범위의 정수를 순서대로 생성하는 이터레이터를 간단하게 구현할 수 있다.

function* createNumbers(from, to) {
	while (from <= to){ yield from++;}
}
let num=createNumbers(10,20)
for(n of num){console.log(n);}

이 코드는 시작값 from부터 종료값 to까지의 정수를 1씩 증가시키며 차례대로 산출한다. 모든 정수를 담은 배열을 메모리에 미리 할당하지 않고, 호출되는 순간에만 값을 계산하여 전달하는 지연 평가(lazy evaluation) 방식을 사용하므로 메모리를 효율적으로 절약한다. 생성된 num 객체는 for...of 문을 통해 10부터 20까지 순차적으로 출력된다.

4. 2차원 배열위의 랜덤찍기

2차원 배열이나 격자 구조에서 특정 좌표를 무작위로 추출할 때도 제너레이터를 응용할 수 있다. 전체 좌표 목록을 매번 배열로 유지하거나 재정렬하지 않고도, 호출할 때마다 중복 없는 무작위 좌표를 계산하여 산출(yield)하도록 설계하면 상태 유지가 단순해진다.


댓글 남기기