ES6에서 도입된 제너레이터(generator)는 코드 블록의 실행을 일시 중지했다가 필요한 시점에 재개할 수 있는 특수한 함수이다.
제너레이터 함수는 function*
키워드로 선언하며, 하나 이상의 yield
표현식을 포함한다(나머지는 일반 함수와 동일).
/* 제너레이터 함수 선언문 */
function* getDecFunc() {
yield 1;
}
/* 제너레이터 함수 표현식 */
const getExpFunc = function* () {
yield 1;
}
/* 제너레이터 메서드 */
const obj = {
* genObjMethod() {
yield 1;
}
}
/* 제너레이터 클래스 메서드 */
class Myclass {
* genClsMethod() {
yield 1;
}
}
단, 제너레이터 함수는 화살표 함수로 정의할 수 없으며, new 연산자와 함께 생성자 함수로 호출할 수 없다.
const genArrowFunc = * () => {
yield 1;
}; // SyntaxError: Unexpected token '*'
function* genFunc() {
yield 1;
}
new genFunc(); // TypeError: genFunc is not a constructor
<aside>
<img src="/icons/chat_gray.svg" alt="/icons/chat_gray.svg" width="40px" /> 애스터리스크 *
의 위치는 function 키워드와 함수 이름 사이라면 어디든지 상관없지만, 일관성을 유지하기 위해 function 키워드 바로 뒤에 붙이는 것을 권장한다.
</aside>
제너레이터 객체는 Symbol.iterator 메서드를 상속받는 이터러블이면서 value, done 프로퍼티를 갖는 이터레이터 리절트 객체를 반환하는 next 메서드를 소유하는 이터레이터이다.
34.1.2 이터레이터 에서 관련 내용을 확인할 수 있다.
function* genFunc() {
yield 1;
yield 2;
yield 3;
}
const generator = genFunc();
console.log(Symbol.iterator in generator); // true
console.loog('next' in generator); // true
제너레이터 객체는 next 메서드를 가지는 이터레이터이지만, 이터레이터에는 없는 return, throw 메서드를 추가로 갖는다.
next 메서드를 호출하면,
제너레이터 함수의 yield 표현식까지 코드 블록을 실행하고 yield된 값을 value 프로퍼티 값으로, false를 done 프로퍼티 값으로 갖는 이터레이터 리절트 객체를 반환한다.
{value: (yield된 값), done: false}
return 메서드를 호출하면,
인수로 전달받은 값을 value 프로퍼티 값으로, true를 done 프로퍼티 값으로 갖는 이터레이터 리절트 객체를 반환한다.
{value: (인수로 전달받은 값), done: true}
throw 메서드를 호출하면,
인수로 전달받은 에러를 발생시키고 undefined를 value 프로퍼티 값으로, true를 done 프로퍼티 값으로 갖는 이터레이터 리절트 객체를 반환한다.
{value: undefined, done: true}
제너레이터는 yield와 next 메서드를 통해 실행을 일시 중지했다가 필요한 시점에 다시 재개할 수 있다.
start -> generatorObj.next() -> yield 1 -> generatorObj.next() -> yield 2 ->
... -> end
제너레이터 객체의 next 메서드를 호출하면 제너레이터 함수의 코드 블록을 yield 표현식 전까지만 실행되고 일시 중지된다. 이때 함수의 제어권이 호출자로 양도(yield)된다.
yield 키워드는 제너레이터 함수의 실행을 일시 중지시키거나 yield 키워드 뒤에 오는 표현식의 평가 결과를 제너레이터 함수 호출자에게 반환한다.
next 메서드를 반복 호출하여 yield 표현식까지 실행과 일시 중지를 반복하다가 제너레이터 함수가 끝까지 실행되면 next 메서드가 반환하는 이터레이터 리절트 객체의 value 프로퍼티에는 제너레이터 함수의 반환값이 할당되고 done 프로퍼티에는 제너레이터 함수가 끝까지 실행되었음을 나타내는 true가 할당된다.
이터레이터의 next 메서드와 달리 제너레이터 객체의 next 메서드에는 인수를 전달할 수 있다. 제너레이터 객체의 next 메서드에 전달한 인수는 제너레이터 함수의 yield 표현식을 할당받는 변수에 할당된다. 이때 yield 표현식을 할당받는 변수에 yield 표현식의 평가 결과가 할당되지 않는 것에 주의해야 한다.
제너레이터 함수는 next 메서드와 yield 표현식을 통해 함수 호출자와 함수의 상태를 주고받을 수 있다. 함수 호출자는 next 메서드를 통해 yield 표현식까지 함수를 실행시켜 제너레이터 객체가 관리하는 상태(yield된 값)를 꺼내올 수 있고, next 메서드에 인수를 전달해서 제너레이터 객체에 상태(yield 표현식을 할당받는 변수)를 밀어넣을 수 있다.
→ 제너레이터의 이런 특성은 동시성 프로그래밍(46.5.2 비동기 처리 )을 가능하게 한다.