보통 무한 루프 코드를 작성할 때 'try-catch' 블록을 사용하는 것은 에러 핸들링을 위해 좋은 방법 중 하나.
하지만 무한 루프가 끝나지 않는 문제를 해결하는 가장 중요한 방법은 루프를 적절하게 종료할 수 있는 조건을 만드는 것!
1. 루프 조건 명확히 하기: 루프가 종료될 수 있는 명확한 조건을 설정
2. 타임아웃 설정: 특정 시간이 지나면 루프를 종료하도록 타임아웃을 설정
3. 에러 핸들링: 'try-catch' 블록을 사용하여 에러 발생 시 루프를 종료하거나 재시도 로직을 작성
4. 외부 신호: 외부 신호나 상태 변수를 사용하여 루프를 제어할 수 있도록 함.
let running = true;
const timeout = setTimeout(() => {
running = false;
onComplete();
}, 60000); // 60 seconds timeout
try {
while (running) {
const { done, value } = await reader.read();
if (done) {
running = false;
onComplete();
break;
}
const data = JSON.parse(decoder.decode(value, { stream: true }).split('data: ')[1]);
if (data.event === 'thread.message.delta' && data.data.delta?.content) {
const chunk = removeAnnotations(removeMarkdown(data.data.delta?.content[0].text.value));
onChunk(chunk);
}
}
} catch (error) {
console.error('Error during streaming:', error);
running = false;
onComplete();
} finally {
clearTimeout(timeout); // Clear the timeout if the loop finishes
}
};
while (true)를 사용하지 않도 재귀함수나 for 루프를 사용할 수도 있다.
(재귀함수란 함수 안에 자신의 함수를 다시 호출하는 함수. 재귀함수는 자신의 로직을 내부적으로 반복하다가, 일정한 조건이 만족되면 함수를 이탈하여 결과를 도출 )
const timeout = setTimeout(() => {
onComplete();
}, 60000); // 60 seconds timeout
const processStream = async () => {
try {
const { done, value } = await reader.read();
if (done) {
onComplete();
clearTimeout(timeout); // Clear the timeout if the loop finishes
return;
}
const data = JSON.parse(decoder.decode(value, { stream: true }).split('data: ')[1]);
if (data.event === 'thread.message.delta' && data.data.delta?.content) {
const chunk = removeAnnotations(removeMarkdown(data.data.delta?.content[0].text.value));
onChunk(chunk);
}
// Call the function recursively
await processStream();
} catch (error) {
console.error('Error during streaming:', error);
onComplete();
clearTimeout(timeout); // Clear the timeout if the loop finishes
}
};
await processStream();
};
processStream 을 사용하여 재귀적으로 reader.read()를 호출하여 데이터를 처리한다. 이렇게 하면 while(ture)를 사용하지 않도 동일한 결과를 얻을 수 있으며 위와 동일하게 타임아웃을 설정하여 무한 루프를 방지할 수 있다.
재귀 호출과 while(true) 루프는 동일한 기능을 수행할 수 있지만, 주된 차이점이 호출 스택 크기에 영향을 미친다!
- 재귀함수는 자신을 호출할 때마다 새로운 함수 호출이 시스템 호출 스택에 쌓이게 된다. 이 과정에서 호출 스택은 각 호출에 대한 정보(함수 매개변수, 지역 변수, 호출 지점 등)을 저장. 호출 스택의 크기는 한정되어 있어 너무 많은 재귀 호출이 발생하면 스택 오버플로우가 발생할 수 있다.
function recursiveFunction() {
// some processing
recursiveFunction(); // self-call
}
다음과 같은 재귀함수가 있을 때 이 함수는 종료 조건이 없으므로 무한히 자신을 호출 -> 결국 시스템 호출 스택을 채워 스택 오버플로우를 유발한다. (주로 재귀가 깊어질 때 문제가 됨)
반면 while(true)루프는 함수 호출 스택을 사용하지 않는다. 반복문은 단순히 코드 블록을 계속 실행할 뿐이며, 추가적인 함수 호출이 발생하지 않는다. 대신 CPU 사용량이 높아질 수 있다.
'Javascript' 카테고리의 다른 글
디바운스(Debounce) (0) | 2023.08.29 |
---|---|
if(a) 과 if(a !== null)이 동일하게 작동하지 않는 이유 (0) | 2023.07.27 |
onAnimationEnd란 (0) | 2023.07.17 |
[Javascript] Javascript가 동적 언어인 이유는 무엇일까?? (0) | 2023.03.15 |
[Javascript] 이벤트루프와 자바스크립트의 비동기 처리 과정 (1) | 2023.03.15 |