개념
함수의 실행을 중단하고 재개할 수 있는 특별한 유형의 함수
`function*` 키워드로 정의되고, 내부에서 `yield` 키워드를 사용하여 값을 반환하고 함수의 실행을 일시 중지할 수 있다.
function* simpleGenerator() {
yield 1;
yield 2;
yield 3;
}
const gen = simpleGenerator();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: undefined, done: true }
`done` 속성
`next()` 메소드는 value와 done 속성을 가지고 있는 객체다. value는 yield에 반환된 값이고, `done`의 속성을 가지고 있다.
무한시퀀스
function* infiniteGenerator() {
let i = 0;
while (true) {
yield i++;
}
}
const gen = infiniteGenerator();
console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
// 계속해서 호출 가능
제너레이터와 for...of 루프
next()를 사용하지 않고 일반 루프 처럼 돌아가는 것이 주목해야할 점
function* simpleGenerator() {
yield 1;
yield 2;
yield 3;
}
for (const value of simpleGenerator()) {
console.log(value); // 1, 2, 3
}
상태유지
상태를 유지하면서 중단 및 재개할 수 있다.
상태 기반 논리가 필요한 경우 유용
function* statefulGenerator() {
let state = 0;
while (true) {
state = yield state;
state += 1;
}
}
const gen = statefulGenerator();
console.log(gen.next().value); // 0
console.log(gen.next(10).value); // 11
console.log(gen.next(20).value); // 21
비동기 작업을 처리하거나 복잡한 데이터 스트림을 다루는데 유용.
즉 async / async와 결합하여 사용될 때 큰 장점을 가진다.
비동기 작업을 순차적으로 실행
function asyncOperation1() {
return new Promise((resolve, reject) => setTimeout(() => resolve({a: 'a'}), 1000))
}
function asyncOperation2(result) {
return new Promise((resolve, reject) => setTimeout(() => resolve({...result, b: 'b'}), 1000))
}
function asyncOperation3(result) {
return new Promise((resolve, reject) => setTimeout(() => resolve({...result, c: 'c'}), 1000))
}
function* asyncTaskGenerator() {
const result1 = yield asyncOperation1();
const result2 = yield asyncOperation2(result1);
const result3 = yield asyncOperation3(result2);
return result3
}
function run(generator) {
const iterator = generator();
function handle(result) {
console.log('handle', result)
if (result.done) return result.value;
return Promise.resolve(result.value).then(res => handle(iterator.next(res)));
}
return handle(iterator.next());
}
/**
* handle { value: Promise { <pending> }, done: false }
* handle { value: Promise { <pending> }, done: false }
* handle { value: Promise { <pending> }, done: false }
* handle { value: { a: 'a', b: 'b', c: 'c' }, done: true }
* final result { a: 'a', b: 'b', c: 'c' }
*/
run(asyncTaskGenerator).then(result => {
console.log('final result', result);
});
스트림에서 제너레이터 함수 사용하는 예
const fs = require('fs');
const readline = require('readline');
async function* readLines(filePath) {
const fileStream = fs.createReadStream(filePath);
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity
}); //파일을 한 줄씩 읽을 수 있는 인터페이스를 생성합니다.
for await (const line of rl) {
// 파일의 각 줄을 읽고 yield 키워드를 사용하여 각 줄을 반환합니다.
console.log('readLines',line)
yield line;
}
}
async function processFile(filePath) {
const lineGenerator = readLines(filePath);
for await (const line of lineGenerator) {
// 여기서 각 줄을 처리할 수 있습니다.
console.log('processFile',line)
}
}
/**
* readLines hello world
* processFile hello world
* readLines it's rainy now
* processFile it's rainy now
*/
processFile('./lowercase.txt');
'IT > javascript' 카테고리의 다른 글
[JS] var 에 대해서 그리고 hoisting 까지 (0) | 2024.09.12 |
---|---|
[javascript] import 자세하게 파해쳐보자 (2) | 2024.09.12 |
[JS] prototype (0) | 2024.04.30 |
[JS] if else 리팩토링 (중첩 조건문 처리하기) > 코드 변환 스냅샷 (0) | 2024.04.29 |
[JS] if else 리펙토링 (객체 + 함수) (0) | 2024.04.29 |