oris9
[Javascript] 제너레이터 함수에 대해 알아보자 본문
제너레이터(generator) 함수란,
단어 자체를 번역하면 생성, 발생시키는 것을 의미한다.
`function*` 키워드를 사용해 생성할 수 있다.
원하는 부분에서 중간에 멈췄다가, 그 부분에서 다시 재개할 수 있는 함수이다.
가장 큰 소수 찾기, 미로통과하기 같은 수학적 문제에 사용할 수 있으며,
계산을 더 작은 단위로 분할해, 병렬 또는 한번에 실행할 수 있으므로 머신러닝 알고리즘 풀이시 대량의 데이터를 처리하는 상황에서 유용한 것이다.
기본적으로 일반 함수는 하나의 값만을 반환하지만
제너레이터 함수는 호출되면 `제너레이터 객체`라는 이터러블 객체를 생성하며, 여러 개의 값을 필요에 따라 하나씩 `반환(yield)`할 수 있다.
제너레이터 객체 메서드
next() : next()를 호출하면 가장 가까운 yield 문을 만날 때까지 실행되고, done과 value 속성을 가지는 객체를 반환한다. 또한 next호출시 여기에 매개변수를 넣어 제너레이터 값을 보낼 수 있다.
return() : 주어진 값을 반환하고 제너레이터를 종료한다.
throw() : 제너레이터에 오류를 발생시키면서 { value: undefined, done : trun }를 반환한다.
** next 호출시 yield 키워드를 가진 문까지 실행이되므로, yield 키워드를 통해 함수를 멈추고 다시 시작하는 시점을 정할 수 있는 것이다.
이터러블 객체와 함께 사용해 데이터 스트림을 쉽게 만들 수 있도록 도와준다.
또한 일반함수와 다르게 함수가 진행되는 동안, 함수 호출자와 양방향으로 함수의 상태를 주고 받을 수 있다는 특징이 있다.
제너레이터 예시로 확인하기
function* generateSequence() {
yield 1;
yield 2;
return 3;
}
// '제너레이터 함수'는 '제너레이터 객체'를 생성합니다.
let generator = generateSequence();
alert(generator); // [object Generator]
function* generateSequence() {
yield 1;
yield 2;
return 3;
}
let generator = generateSequence();
let one = generator.next();
// 첫 번째 yield 키워드가 발견될 때까지 생성기 함수에서 코드가 실행되며, 이 시점에서 실행을 일시 중지하고 산출된 값(yielded value)을 반환
alert(JSON.stringify(one)); // {value: 1, done: false}
let two = generator.next();
// 중지된 지점에서 실행을 다시 시작하고 다음으로 산출된 값(yielded value)을 생성
alert(JSON.stringify(two)); // {value: 2, done: false}
let three = generator.next();
// 실행은 return문에 다다르고 함수가 종료
alert(JSON.stringify(three)); // {value: 3, done: true}
let four = generator.next();
// 제너레이터가 종료됐으므로 계속 next를 호출해도 done: true가 반환될 뿐이다.
alert(JSON.stringify(four)); // {done: true}
제너레이터 객체 확인하기
function* generateSequence() {
yield 1;
yield 2;
return 3;
}
let generator = generateSequence(); // generator는 이터러블 객체
for(let value of generator) {
alert(value); // 1, 2가 출력됨( ** done: true일 때 마지막 value를 무시 )
}
function* generateSequence() {
yield 1;
yield 2;
yield 3;
}
let generator = generateSequence();
for(let value of generator) {
alert(value); // 1, 2, 3
}
이와 같은 루프에서 next() 메서드를 호출하면 산출된 값을 한 번에 하나씩 처리할 수 있으므로 자바스크립트 프로그램의 메인 스레드를 차단하지 않고 장기 실행 계산을 수행하거나 대량의 데이터를 처리할 수 있다.
비동기 키워드와 함께 사용하기
async function generateValues() {
yield 1;
yield 2;
yield 3;
}
async function consumeValues() {
const generator = generateValues();
const firstValue = await generator.next(); // { value: 1, done: false }
const secondValue = await generator.next(); // { value: 2, done: false }
const thirdValue = await generator.next(); // { value: 3, done: false }
}
위의 코드에서 consumeValues() 함수는 await 키워드를 사용하여 실행을 일시 중지하고 generator가 각 값을 반환할 때까지 기다립니다. 이는 asynchronous이고 non-blocking적인 상태에서 코드를 더 synchronous으로 보이는 스타일로 작성할 수 있게 해준다.
무한 제너레이터
제너레이터 함수를 사용하면 값은 필요할 때까지 계산되지 않으므로 제너레이터는 잠재적으로 무한한 데이터 구조를 정의할 수 있다.
function* infinite() {
let index = 0;
while (true) {
yield index++;
}
}
const generator = infinite(); // "Generator { }"
console.log(generator.next().value); // 0
console.log(generator.next().value); // 1
console.log(generator.next().value); // 2
// ...
아직 이해가 안되는 부분
- 재귀함수 구현하기
generator를 사용하여 재귀 함수를 생성하려면 yield* 키워드를 사용하여 generator 함수 내에서 재귀적으로 generator 함수를 호출하는 방식으로 구현할 수 있습니다.
이를 통해 generator 함수는 각 재귀 호출에서 실행을 일시 중지하고 다시 시작할 수 있으며, 시간이 지남에 따라 일련의 값을 생성할 수 있습니다.
다음은 재귀 함수를 구현하는 방법의 예입니다.
function* myGenerator(n) {
if (n <= 0) {
// base case: return the initial value
return 0;
} else {
// recursive case: yield the current value and call the generator recursively
yield n;
yield* myGenerator(n - 1);
}
}
이 예제에서, myGenerator 함수 작업은 argument로 받은 n부터 0까지 값을 생성하는 계산을 재귀적으로 수행합니다. 이 함수를 사용하려면 next() 메서드를 호출하여 한 번에 하나씩 값을 return 받아 처리할 수 있습니다.
다음은 myGenerator 기능을 사용하는 방법의 예입니다.
// continue getting yielded values until the generator is finished
for (const result of myGenerator(5)) {
doSomethingWithResult(result);
}
이러한 방식으로 JavaScript 생성기를 사용하면 언제든지 실행을 일시 중지했다가 다시 시작할 수 있는 방식으로 재귀 계산을 수행할 수 있으므로 오래 실행되거나 복잡한 계산을 더 쉽게 관리할 수 있습니다.
https://velog.io/@dessin/JavaScript-Generator%EB%A1%9C-DFS-BFS-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0
**이터러블 객체 먼저 공부
- 이터러블 대신 제너레이터 사용하기
iterable 객체를 다룬 챕터에서 from..to 사이에 있는 값을 반환하는 반복 가능 객체, range를 만들어 보았습니다.
https://ko.javascript.info/generators
참고
https://seo-tory.tistory.com/77
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Generator/next
https://velog.io/@dessin/JavaScript-Generator%EB%A1%9C-DFS-BFS-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0
'JavaScript' 카테고리의 다른 글
[Javascript] var, let, const 열심히 비교해보기 (0) | 2024.03.30 |
---|---|
[Javascript] ECMA스크립트(ECMAScript, 또는 ES) (0) | 2024.03.25 |
[Javascript] 정규표현식(RegExp, regular expression) 정리하기 (0) | 2024.03.11 |
[Javascript] 유용한 배열 메서드 정리하기 (0) | 2024.03.10 |
[Javascript] 파라미터? 인자? 헷갈리는 용어 정리와 argument 객체, 나머지 매개변수에 대해 알아보기 (0) | 2024.03.09 |