코드 블록의 실행을 일시 중지 (블로킹) 했다가 필요한 시점에 재개할 수 있는 특수한 함수다.
일반 함수는 하나의 값만을 반환하지만 제너레이터를 사용하면여러 개의 값을 필요에 따라 하나씩 반환(yield)할 수 있다.
function*
키워드를 이용
function* generateSequence() {
yield 1;
yield 2;
return 3;
}
제너레이터 함수를 호출하면 코드가 실행되지 않고, 대신 실행을 처리하는 특별 객체 제너레이터 객체
가 반환된다.
function* generateSequence() {
yield 1;
yield 2;
return 3;
}
// '제너레이터 함수'는 '제너레이터 객체'를 생성한다.
// 아직 함수 본문 코드는 실행되지 않았다.
let generator = generateSequence();
alert(generator); // [object Generator]
next() 메서드
는 제너레이터의 주요 메서드이다.
가장 가까운 yield <value>
문을 만날 때까지 실행이 지속되며 value
를 생략할 수 있는데 이 경우에는 undefined
가 된다.
yield <value>
문을 만나면 실행이 멈추고 산출하고자 하는 값인 value
가 바깥 코드에 반환된다.
next()
는 항상 두 프로퍼티를 가진 객체를 반환한다.
value
: 산출 값done
: 함수 코드 실행이 끝났으면 true
, 아니라면 false
function* generateSequence() {
yield 1;
yield 2;
return 3;
}
let generator = generateSequence();
let one = generator.next();
alert(JSON.stringify(one)); // {value: 1, done: false}
// 현재로서는 첫 번째 값만 받았으므로 함수 실행은 두 번째 줄에서 멈췄다.
// 다시 호출
let two = generator.next();
alert(JSON.stringify(two)); // {value: 2, done: false}
// 다시 호출하면 실행은 return문에 다다르고 함수가 종료
let three = generator.next();
alert(JSON.stringify(three)); // {value: 3, done: true} 종료
for..of
반복문을 사용해 값을 얻을 수 있고 전개문법(...)
으로도 가능
function* generateSequence() {
yield 1;
yield 2;
return 3;
}
let generator = generateSequence();
for(let value of generator) {
alert(value); // 1, 2가 출력됨
}
3은 출력되지 않는다. for..of
이터레이션이 done:true
일 때 마지막value
를 무시하기 때문에 yield : 3
으로 바꿔야 값이 반환됨
function* generateSequence() {
yield 1;
yield 2;
yield 3;
}
let sequence = [0, ...generateSequence()];
alert(sequence); // 0, 1, 2, 3
yield
를 사용해 제너레이터 안,밖으로 정보 교화yield
가 양방향 길 같은 역할을 한다. 즉, 결과를 바깥으로 전달할 뿐만 아니라 값을 제너레이터 안으로 전달한다.
값을 안,밖으로 전달하라면 generator.next(arg)
를 호출해야 한다. 이 때arg
는 yield
의 결과가 된다.
function* gen() {
// 질문을 제너레이터 밖 코드에 던지고 답을 기다립니다.
let result = yield "2 + 2 = ?"; // (*)
alert(result);
}
let generator = gen();
let question = generator.next().value; // <-- yield는 value를 반환합니다.
generator.next(4); // --> 결과를 제너레이터 안으로 전달합니다
1.generator.next()
를 처음 호출할 땐 항상 인수가 없어야 한다. 그래서 generator.next()
를 호출하면 실행이 시작되고 첫번 째yield "2 + 2 = ?"
의 결과가 반환된다.
2.yield
의 결과가 제너레이터를 호출하는 외부 코드에 있는 변수 question
에 할당
3.generator.next(4)
에서 제너레이터가 다시 시작되고 4는 result에 할당
function* gen() {
let ask1 = yield "2 + 2 = ?";
alert(ask1); // 4
let ask2 = yield "3 * 3 = ?"
alert(ask2); // 9
}
let generator = gen();
alert( generator.next().value ); // "2 + 2 = ?"
alert( generator.next(4).value ); // "3 * 3 = ?"
alert( generator.next(9).done ); // true
generator.throw
결과가 될 것을 제너레이터 안에 전달하기도 하고 외부 코드가 에러를 만들거나 던질 수도 있다.
에러를 yield
안으로 전달하려면 generator.throw(err)
를 호출해야한다. 호출하면 err
는 yield
가 있는 줄로 던져진다.
function* gen() {
try {
let result = yield "2 + 2 = ?"; // (1)
alert("위에서 에러가 던져졌기 때문에 실행 흐름은 여기까지 다다르지 못합니다.");
} catch(e) {
alert(e); // 에러 출력
}
}
let generator = gen();
let question = generator.next().value;
generator.throw(new Error("데이터베이스에서 답을 찾지 못했습니다.")); // (2)