1. 제너레이터(Generator)란

제너레이터란 ES6에서 새롭게 도입된 개념의 함수로, 코드 실행을 중간에 멈췄다가 필요한 시점에 재개할 수 있는 특징을 가진다. 일반적인 함수는 함수를 호출해 실행되는 순간 제어할 수 없지만 제너레이터는 이것이 가능하고 이를 이용해 비동기 처리를 동기 처리처럼 프로그래밍 할 수 있다.

1.1 제너레이터 함수 정의

일반 함수를 정의하는 방식과 같지만, 다른 몇 가지가 있다. 첫 번째, function 키워드 옆에 별표(*, 에스터리스크)를 붙여서 사용한다. 두 번째, 함수 내에서 return과 비슷한 개념인 yield를 사용해 코드의 실행을 제어 가능하게 한다. 그리고 화살표 함수, new 연산자는 사용 불가하다.

function* 제너레이터1() {
	yield 1;
	yield 2;
	yield 3;
}
// 기본형

function* 제너레이터2() {
	for (const element of [1, 2, 3]) {
		yield element;
	}
}

function* 제너레이터3() {
	yield* [1, 2, 3];
}
// yield*으로 또 다른 이터러블 객체를 위임해서 사용할 수 있다.

const 이터레이터 = 제너레이터1();
console.log(이터레이터.next())
console.log(이터레이터.next())
console.log(이터레이터.next())
console.log(이터레이터.next())
console.log(이터레이터.next())

여기서 yield를 사용하면 비동기처리를 동기처럼 프로그래밍 할 수 있다.

function* 제너레이터1() {
	yield 비동기함수1();
	yield 비동기함수2();
	yield 비동기함수3();
}

이는 async/await 방식으로도 처리할 수 있다. 따라서 각각의 특성을 이해하고, 용도에 맞게 사용하는 편이 좋다.

async function 제너레이터1() {
	await 비동기함수1();
	await 비동기함수2();
	await 비동기함수3();
}

관련되어 다양한 아티클을 확인하고 싶다면 비동기처리 async await generator로 google에 검색해보길 권한다.

1.2 제너레이터의 특징

제너레이터 함수는 일반적인 자바스크립트 함수와는 다른 특징을 가진다. 함수 동작을 빠져나갔다가 다시 돌아올 수 있다는 점, 실행 시 Generator 객체를 생성해 반환한다는 점, 반복되는 작업을 무한 루프와 yield로 구현할(비동기 통신도 무한 재실행 구현할 수 있다) 수 있다는 점이 대표적이다.

1.2.1 함수 동작을 빠져나갔다가 다시 돌아올 수 있다

일반적인 함수는 함수를 한 번 실행시키면, 함수 내부에서 return을 만날 때까지 함수를 구성하는 코드들을 위에서부터 아래로 계속 실행시킨다. 하지만 제너레이터 함수는 yield 명령어를 통해 동작 중에 함수를 빠져나올 수 있을 뿐 아니라 함수 외부에서 제너레이터를 다시 호출함으로써 코드를 중단점에서부터 다시 실행시킬 수 있다. 즉, 함수의 제어권을 함수 호출자와 주고 받는다고 볼 수 있다.

1.2.2 Generator 객체를 생성해 반환한다

제너레이터 함수를 호출했을 때, 함수 내부의 코드를 즉시 실행하는 것이 아니라 우선 Generator 객체를 생성(이터러블 생성)해 반환한다.

콘솔에서 아래의 코드를 실행해보면 제너레이터 함수 실행 시 반환되는 객체를 확인할 수 있다.

// 제너레이터 함수 generatorFunc를 생성
function* generatorFunc() {};

// generatorFunc의 반환값을 console.dir로 출력
console.dir(generatorFunc());

제너레이터 함수 generatorFunc 내부에서는 수동으로 return을 지정해주지 않았지만, 실행시키면 아래처럼 generatorFunc 객체가 반환되어 console.dir로 출력된 구조를 확인할 수 있다.