이 글은 You Don't Know JS 서적을 참고하여 작성하였습니다.
**
제너레이터**는 추론/실용적이고 동기/순차적 형태로 비동기 흐름 제어를 가능하게 해주는 기능이다. 즉, **제너레이터**는 내부 코드를 동기/순차적 형태의 일련의 작업 단계로 자연스럽게 표현할 수 있게끔 ****도와준다.
일반적인 함수는 실행될 때 제어권을 호출부에 넘기지 않고 완전하게 실행된다.
선점형 멀티스레드 환경에서는 스레드의 제어권이 바뀌면서 중간에 다른 함수가 실행될 수는 있겠으나, 자바스크립는 단일 스레드이다.
하지만, 자바스크립트는 협동적 동시성을 달성하기 위해 제너레이터 기능을 제공한다.
제너레이터선언하는 경우, 함수 앞에*키워드를 추가하는 것 이 외에는 기본적인 함수 체계와 동일하다.(제너레이터도 함수이다.)
let global = 0;
function *foo() {
global++;
yield;
console.log(global);
}
function bar() {
global++;
}
const iter = foo();
iter.next();
bar();
iter.next();
// 2
그럼 위 예제를 통해 제어권이 어떻게 이동하는 지 흐름을 살펴보자.
foo() 함수 호출은 단순히 *foo() 제너레이터를 실행하는 것이 아닌, 제너레이터 실행을 제어할 iterator를 반환한다.iterator**가 next() 함수를 호출하면, *foo() 제너레이터를 yield 키워드까지 실행을 하고 멈춰 대기한다.iterator**가 next() 함수를 호출하면, yield 키워드 부분에서 멈춰있던 *foo() 제너레이터를 함수 종료(반환)할 때까지 실행하고 끝마친다.위와 같은 과정에서, 제너레이터는 실행 중에 yield 문에서 잠시 중지하고 대기하는 것을 확인할 수 있다.
뿐만 아니라, 제너레이터 함수 호출시 제너레이터를 제어하는 Iterator 객체를 생성해 반환하는데 next() 함수를 이용해 제너레이터의 현재 위치에서 다음 yield 또는 제너레이터 끝까지 실행한다.
next() 함수의 반환값은 제너레이터 함수가 반환한 값을 value 프로퍼티에 저장한 객체이다.
{
value: "반환값"
}
즉 yeild 문은 중간 반환값을 next() 함수의 반환값으로 전달하고, 동시에 제어권을 next() 호출부로 넘긴다.
이러한 부분들이 가능한 것은 제너레이터가 yield, next()라는 강력한 입출력 기능을 가지고 있기 때문이다.
아래의 예제를 살펴보자.