2022. 11. 07 스터디 내용
참고
https://ko.javascript.info/generators-iterators
제너레이터와 비동기 이터레이션
ko.javascript.info
제너레이터 (Generator)
일반적인 함수는 하나의 값을 반환함. 제너레이터는 여러개의 값을 필요에 따라서 하나씩 반환 할 수 있도록 해줌.
* 비동기 처리에 유용하게 사용됨.
function* commonFunc() {
return 1;
}
function* generatorFunc() {
yield 1; // 첫번째 반환 값
yield 2; // 두번째 반환 값
return 3; // 세번째 반환 값
}
제너레이터 함수
제너레이터를 사용하기 위해서는 제너레이터 함수(function* 함수명(){...})가 필요함.
함수를 호출하면, 코드는 실행되지 않고 제너레이터 객체(이터러블)를 반환함.
* 화살표 함수를 사용할 수 없음
제너레이터 객체
제너레이터 객체는 next() 메서드를 가짐.
next( )는 가장 가까운 yield 문까지 코드를 실행하고, 객체를 반환함. 이 객체는 value, done 프로퍼티를 가짐.
- value: 반환 값
- done: 함수 코드가 끝났는지 여부 (true: 끝남 / false: 함수 진행중)
function* generatorFunc() {
console.log("첫번째 호출");
yield 1;
console.log("두번째 호출");
yield 2;
console.log("세번째 호출");
return 3; // 또는 yield 3;
}
let generator = generatorFunc();
generator.next(); //{value:1, done:false}
generator.next(); //{value:2, done:false}
generator.next(); //{value:3, done:true}
yield 키워드
결과를 제너레이터 밖으로 보내기도 하지만, 밖에서부터 안으로 받아올 수도 있음.
function* generatorFunc() {
let first = yield "1 + 1 = ?";
let secsond = yield "2 + 2 = ?";
}
let generator = generatorFunc();
let result1 = generator.next().value;
let result2 = generator.next(2).value;
let result3 = generator.next(4).done;
function* generatorFunc() {
let first = yield "1 + 1 = ?";
let secsond = yield "2 + 2 = ?";
}
let generator = generatorFunc();
let result1 = generator.next().value;
// result1 = "1 + 1 = ?"
let result2 = generator.next(2).value;
// first = 2
// result2 = "2 + 2 = ?"
let result3 = generator.next(4).done;
// second = 4
// result3 = true
이터러블 (iterable, 반복 가능한)
제너레이터 객체는 이터러블 객체이므로 for .. of 반복문과 전개 문법(…)을 사용할 수 있음.
(단, done:true일 때의 value값을 무시하므로 주의할 것)
function* generatorFunc() {
yield 1;
yield 2;
return 3; // **
}
let generator = generatorFunc();
for(let value of generator) {
console.log(value); //1, 2 출력
}
let arr = [...generatorFunc()] //1, 2
function* generatorFunc() {
yield 1;
yield 2;
yield 3; // **
}
let generator = generatorFunc();
for(let value of generator) {
console.log(value); //1, 2, 3 출력
}
let arr = [...generatorFunc()] //1, 2, 3
제너레이터 컴포지션
yield* 키워드를 사용하여 제너레이터 안에 제너레이터를 임베딩(embedding, composing) 할 수 있음.
실행 결과(산출값)를 바깥으로 전달함.
🔽 아래 코드는 중첩 제네레이터를 사용하는 것과 같은 역할을 함.
function* generateSequence(start, end) {
for (let i = start; i <= end; i++)
yield i;
}
function* generatePasswordCodes() {
// 0..9
yield* generateSequence(48, 57);
// A..Z
yield* generateSequence(65, 90);
// a..z
yield* generateSequence(97, 122);
}
let str = '';
for(let code of generatePasswordCodes()) {
str += String.fromCharCode(code);
}
alert(str); // 0..9A..Za..z
예외처리
제너레이터객체.throw()를 사용해 에러를 전달할 수 있음.
에러에 대한 예외처리는 제너레이터 함수 내부, 또는 함수 호출 위치에서 할 수 있음.
🔽 제네레이터 함수 내에서 예외처리를 하는 경우
function* generatorFunc() {
try {
let first = yield "1 + 1 = ?";
alert("yield에서 에러 발생하지 않음");
} catch(e) {
alert(e); // error message
}
}
let generator = generatorFunc();
let result = generator.next().value;
generator.throw(new Error("error message")); // 에러 발생
🔽 제네레이터 함수 호출 부분에서 예외처리를 하는 경우
function* generatorFunc() {
let first = yield "1 + 1 = ?";
}
let generator = generatorFunc();
let result = generator.next().value;
try {
**generator.throw(new Error("error message"))**; // 에러 발생
} catch(e) {
alert(e); // error message
}
async 이터레이터와 제너레이터
비동기 이터레이터/비동기 제너레이터를 사용하여 비동기적으로 데이터를 받을 수 있음. 주로 네트워크 프로그래밍 등에 쓰임.
비동기 이터레이터 (Async Iterator)
일반 이터레이터와 비슷하지만, 다음과 같은 차이점이 있음.
- Symbol.iterator대신 Symbol.asyncIterator 를 사용해야함.
- next() 메서드는 반드시 Promise를 반환해야함.
- 비동기 이터레이터 객체를 사용한 반복문을 호출할 때에는, 반드시 await를 사용해야함.
- 비동기 이터레이터 객체는 전개 문법을 사용할 수 없음.
🔽 일반 이터러블 객체
let range = {
from: 1,
to: 5,
[Symbol.iterator]() {
return {
current: this.from,
last: this.to,
next() {
if (this.current <= this.last) {
return { done: false, value: this.current++ };
} else {
return { done: true };
}
}
};
}
};
for(let value of range) {
alert(value); // 1, 2, 3, 4, 5
}
🔽 비동기 이터레이터 객체
let range = {
from: 1,
to: 5,
[Symbol.asyncIterator]() {
return {
current: this.from,
last: this.to,
async next() {
await new Promise(resolve => setTimeout(resolve, 1000))
if (this.current <= this.last) {
return { done: false, value: this.current++ };
} else {
return { done: true };
}
}
};
}
};
(async () => {
for await (let value of range) {
alert(value); // 1,2,3,4,5
}
})()'그 외' 카테고리의 다른 글
| [pgAdmin][Error] FATAL: connection requires a valid client certificate (0) | 2025.09.16 |
|---|---|
| [langchain] document loader (0) | 2025.09.15 |
| [JS] 프라미스와 async, await 정리 (0) | 2025.09.08 |
| [Git] 기초 (0) | 2025.09.03 |