Generator는 빠져나갔다가 나중에 다시 돌아올 수 있는 함수다.
파일 업로드 처리하는데, 동시에 처리하는 파일의 개수를 제한할 필요가 있었다. while과 setInterval 조합으로 처리하려다가 좀 더 세련되고, 최근 기술을 사용하고 싶어서 Generator를 사용했다.
1번 예제는 써도 괜찮지만 2번 예제는 보완이 필요해 보인다.
비동기 함수를 순차적으로 실행하는 예제
다음은 Generator를 사용해서 비동기 함수를 순차적으로 실행하는 간단한 코드다.
// 실행하려는 비동기 함수
function PromiseFunc(i) {
return new Promise((resolve) => {
setTimeout(() => {
console.log('returned', i)
resolve();
}, 1000);
});
}
// 이터레이터를 만드는 함수. *과 yield 사용
function* getIterator() {
for (let i=0; i<10; i++) {
yield PromiseFunc(i);
}
}
// 이터레이터를 가져온다.
const it = getIterator();
(function nextItem(val) {
// ret = {value: ..., done: true or false}
let ret = it.next(val);
// 이터레이터의 다음이 있는지?
if(!ret.done) {
ret.value.then(nextItem);
} else {
console.log("finished");
}
})()
동시에 10개씩 처리하는 예제
이번에는 10개씩 동시 처리하는 예제다.
// 실행하려는 비동기 함수
function PromiseFunc(i) {
return new Promise((resolve) => {
console.log('invoked', i)
// 비동기 처리
setTimeout(() => {
console.log('returned', i)
resolve(i);
}, 1000);
});
}
// 이터레이터를 만드는 함수. *과 yield 사용
function* getIterator() {
for (let i=0; i<100; i++) {
yield PromiseFunc(i);
}
}
// 이터레이터를 가져온다.
const it = getIterator();
// 동시에 처리할 개수 지정
const CONCURRENT = 10;
// 카운트 초기화
let cnt = 0;
// 처리 시작
(function nextItem() {
let ret = it.next();
// 카운트 증가
cnt++;
if(!ret.done) {
ret.value.then(() => {
// 처리가 완료되어 카운트 감소
cnt--;
});
let timer = setInterval(() => {
if(cnt < CONCURRENT) {
nextItem();
clearInterval(timer);
}
}, 0);
} else {
console.log("finished");
}
})()